diff --git a/Shared/Coordinators/LiveTVTabCoordinator.swift b/Shared/Coordinators/LiveTVTabCoordinator.swift index afcf7ab8..83903c7a 100644 --- a/Shared/Coordinators/LiveTVTabCoordinator.swift +++ b/Shared/Coordinators/LiveTVTabCoordinator.swift @@ -32,7 +32,7 @@ final class LiveTVTabCoordinator: TabCoordinatable { func makeProgramsTab(isActive: Bool) -> some View { HStack { Image(systemName: "tv") - Text("Programs") + L10n.programs.text } } @@ -44,7 +44,7 @@ final class LiveTVTabCoordinator: TabCoordinatable { func makeChannelsTab(isActive: Bool) -> some View { HStack { Image(systemName: "square.grid.3x3") - Text("Channels") + L10n.channels.text } } @@ -56,7 +56,7 @@ final class LiveTVTabCoordinator: TabCoordinatable { func makeHomeTab(isActive: Bool) -> some View { HStack { Image(systemName: "house") - Text("Home") + L10n.home.text } } } diff --git a/Shared/Coordinators/MainCoordinator/tvOSMainTabCoordinator.swift b/Shared/Coordinators/MainCoordinator/tvOSMainTabCoordinator.swift index d4ff0f5b..e62e24b7 100644 --- a/Shared/Coordinators/MainCoordinator/tvOSMainTabCoordinator.swift +++ b/Shared/Coordinators/MainCoordinator/tvOSMainTabCoordinator.swift @@ -43,26 +43,26 @@ final class MainTabCoordinator: TabCoordinatable { } func makeTv() -> NavigationViewCoordinator { - NavigationViewCoordinator(TVLibrariesCoordinator(viewModel: TVLibrariesViewModel(), title: "TV Shows")) + NavigationViewCoordinator(TVLibrariesCoordinator(viewModel: TVLibrariesViewModel(), title: L10n.tvShows)) } @ViewBuilder func makeTvTab(isActive: Bool) -> some View { HStack { Image(systemName: "tv") - Text("TV Shows") + L10n.tvShows.text } } func makeMovies() -> NavigationViewCoordinator { - NavigationViewCoordinator(MovieLibrariesCoordinator(viewModel: MovieLibrariesViewModel(), title: "Movies")) + NavigationViewCoordinator(MovieLibrariesCoordinator(viewModel: MovieLibrariesViewModel(), title: L10n.movies)) } @ViewBuilder func makeMoviesTab(isActive: Bool) -> some View { HStack { Image(systemName: "film") - Text("Movies") + L10n.movies.text } } @@ -74,7 +74,7 @@ final class MainTabCoordinator: TabCoordinatable { func makeOtherTab(isActive: Bool) -> some View { HStack { Image(systemName: "folder") - Text("Other") + L10n.other.text } } diff --git a/Shared/Errors/NetworkError.swift b/Shared/Errors/NetworkError.swift index 8e68b2eb..fc5052bd 100644 --- a/Shared/Errors/NetworkError.swift +++ b/Shared/Errors/NetworkError.swift @@ -67,7 +67,7 @@ enum NetworkError: Error { { let errorMessage: ErrorMessage - var logMessage = "An error has occurred." + var logMessage = L10n.unknownError var logConstructor = logConstructor switch response { @@ -77,14 +77,14 @@ enum NetworkError: Error { // https://developer.apple.com/documentation/foundation/1508628-url_loading_system_error_codes switch err._code { case -1001: - logMessage = "Network timed out." + logMessage = L10n.networkTimedOut logConstructor.message = logMessage errorMessage = ErrorMessage(code: err._code, - title: "Timed Out", + title: L10n.error, displayMessage: displayMessage, logConstructor: logConstructor) case -1004: - logMessage = "Cannot connect to host." + logMessage = L10n.cannotConnectToHost logConstructor.message = logMessage errorMessage = ErrorMessage(code: err._code, title: L10n.error, @@ -128,7 +128,7 @@ enum NetworkError: Error { { let errorMessage: ErrorMessage - var logMessage = "An error has occurred." + var logMessage = L10n.unknownError var logConstructor = logConstructor switch response { @@ -137,10 +137,10 @@ enum NetworkError: Error { // Generic HTTP status codes switch code { case 401: - logMessage = "User is unauthorized." + logMessage = L10n.unauthorizedUser logConstructor.message = logMessage errorMessage = ErrorMessage(code: code, - title: "Unauthorized", + title: L10n.unauthorized, displayMessage: displayMessage, logConstructor: logConstructor) default: diff --git a/Shared/Extensions/JellyfinAPIExtensions/BaseItemDtoExtensions.swift b/Shared/Extensions/JellyfinAPIExtensions/BaseItemDtoExtensions.swift index e9f7aae0..9e970949 100644 --- a/Shared/Extensions/JellyfinAPIExtensions/BaseItemDtoExtensions.swift +++ b/Shared/Extensions/JellyfinAPIExtensions/BaseItemDtoExtensions.swift @@ -248,15 +248,15 @@ public extension BaseItemDto { var informationItems: [ItemDetail] = [] if let productionYear = productionYear { - informationItems.append(ItemDetail(title: "Released", content: "\(productionYear)")) + informationItems.append(ItemDetail(title: L10n.released, content: "\(productionYear)")) } if let rating = officialRating { - informationItems.append(ItemDetail(title: "Rated", content: "\(rating)")) + informationItems.append(ItemDetail(title: L10n.rated, content: "\(rating)")) } if let runtime = getItemRuntime() { - informationItems.append(ItemDetail(title: "Runtime", content: runtime)) + informationItems.append(ItemDetail(title: L10n.runtime, content: runtime)) } return informationItems @@ -267,12 +267,7 @@ public extension BaseItemDto { if let container = container { let containerList = container.split(separator: ",").joined(separator: ", ") - - if containerList.count > 1 { - mediaItems.append(ItemDetail(title: "Containers", content: containerList)) - } else { - mediaItems.append(ItemDetail(title: "Container", content: containerList)) - } + mediaItems.append(ItemDetail(title: L10n.containers, content: containerList)) } if let mediaStreams = mediaStreams { @@ -280,15 +275,15 @@ public extension BaseItemDto { let subtitleStreams = mediaStreams.filter { $0.type == .subtitle } if !audioStreams.isEmpty { - let audioList = audioStreams.compactMap { "\($0.displayTitle ?? "No Title") (\($0.codec ?? "No Codec"))" } + let audioList = audioStreams.compactMap { "\($0.displayTitle ?? L10n.noTitle) (\($0.codec ?? L10n.noCodec))" } .joined(separator: ", ") - mediaItems.append(ItemDetail(title: "Audio", content: audioList)) + mediaItems.append(ItemDetail(title: L10n.audio, content: audioList)) } if !subtitleStreams.isEmpty { - let subtitleList = subtitleStreams.compactMap { "\($0.displayTitle ?? "No Title") (\($0.codec ?? "No Codec"))" } + let subtitleList = subtitleStreams.compactMap { "\($0.displayTitle ?? L10n.noTitle) (\($0.codec ?? L10n.noCodec))" } .joined(separator: ", ") - mediaItems.append(ItemDetail(title: "Subtitles", content: subtitleList)) + mediaItems.append(ItemDetail(title: L10n.subtitles, content: subtitleList)) } } diff --git a/Shared/Generated/Strings.swift b/Shared/Generated/Strings.swift index b18f4dde..2d52cfe5 100644 --- a/Shared/Generated/Strings.swift +++ b/Shared/Generated/Strings.swift @@ -1,11 +1,3 @@ -// -// Swiftfin is subject to the terms of the Mozilla Public -// License, v2.0. If a copy of the MPL was not distributed with this -// file, you can obtain one at https://mozilla.org/MPL/2.0/. -// -// Copyright (c) 2022 Jellyfin & Jellyfin Contributors -// - // swiftlint:disable all // Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen @@ -18,194 +10,385 @@ import Foundation // swiftlint:disable explicit_type_interface function_parameter_count identifier_name line_length // swiftlint:disable nesting type_body_length type_name vertical_whitespace_opening_braces internal enum L10n { - /// Accessibility - internal static let accessibility = L10n.tr("Localizable", "accessibility") - /// Add URL - internal static let addURL = L10n.tr("Localizable", "addURL") - /// All Genres - internal static let allGenres = L10n.tr("Localizable", "allGenres") - /// All Media - internal static let allMedia = L10n.tr("Localizable", "allMedia") - /// Appearance - internal static let appearance = L10n.tr("Localizable", "appearance") - /// Apply - internal static let apply = L10n.tr("Localizable", "apply") - /// Audio & Captions - internal static let audioAndCaptions = L10n.tr("Localizable", "audioAndCaptions") - /// Audio Track - internal static let audioTrack = L10n.tr("Localizable", "audioTrack") - /// Back - internal static let back = L10n.tr("Localizable", "back") - /// CAST - internal static let cast = L10n.tr("Localizable", "cast") - /// Change Server - internal static let changeServer = L10n.tr("Localizable", "changeServer") - /// Closed Captions - internal static let closedCaptions = L10n.tr("Localizable", "closedCaptions") - /// Connect - internal static let connect = L10n.tr("Localizable", "connect") - /// Connect Manually - internal static let connectManually = L10n.tr("Localizable", "connectManually") - /// Connect to Jellyfin - internal static let connectToJellyfin = L10n.tr("Localizable", "connectToJellyfin") - /// Connect to Server - internal static let connectToServer = L10n.tr("Localizable", "connectToServer") - /// Continue Watching - internal static let continueWatching = L10n.tr("Localizable", "continueWatching") - /// Dark - internal static let dark = L10n.tr("Localizable", "dark") - /// DIRECTOR - internal static let director = L10n.tr("Localizable", "director") - /// Discovered Servers - internal static let discoveredServers = L10n.tr("Localizable", "discoveredServers") - /// Display order - internal static let displayOrder = L10n.tr("Localizable", "displayOrder") - /// Empty Next Up - internal static let emptyNextUp = L10n.tr("Localizable", "emptyNextUp") - /// Episodes - internal static let episodes = L10n.tr("Localizable", "episodes") - /// Error - internal static let error = L10n.tr("Localizable", "error") - /// Existing Server - internal static let existingServer = L10n.tr("Localizable", "existingServer") - /// Filter Results - internal static let filterResults = L10n.tr("Localizable", "filterResults") - /// Filters - internal static let filters = L10n.tr("Localizable", "filters") - /// Genres - internal static let genres = L10n.tr("Localizable", "genres") - /// Home - internal static let home = L10n.tr("Localizable", "home") - /// Latest %@ - internal static func latestWithString(_ p1: Any) -> String { - L10n.tr("Localizable", "latestWithString", String(describing: p1)) - } - - /// Library - internal static let library = L10n.tr("Localizable", "library") - /// Light - internal static let light = L10n.tr("Localizable", "light") - /// Loading - internal static let loading = L10n.tr("Localizable", "loading") - /// Local Servers - internal static let localServers = L10n.tr("Localizable", "localServers") - /// Login - internal static let login = L10n.tr("Localizable", "login") - /// Login to %@ - internal static func loginToWithString(_ p1: Any) -> String { - L10n.tr("Localizable", "loginToWithString", String(describing: p1)) - } - - /// More Like This - internal static let moreLikeThis = L10n.tr("Localizable", "moreLikeThis") - /// Next Up - internal static let nextUp = L10n.tr("Localizable", "nextUp") - /// No Cast devices found.. - internal static let noCastdevicesfound = L10n.tr("Localizable", "noCastdevicesfound") - /// No results. - internal static let noResults = L10n.tr("Localizable", "noResults") - /// Type: %@ not implemented yet :( - internal static func notImplementedYetWithType(_ p1: Any) -> String { - L10n.tr("Localizable", "notImplementedYetWithType", String(describing: p1)) - } - - /// Ok - internal static let ok = L10n.tr("Localizable", "ok") - /// Other User - internal static let otherUser = L10n.tr("Localizable", "otherUser") - /// Page %1$@ of %2$@ - internal static func pageOfWithNumbers(_ p1: Any, _ p2: Any) -> String { - L10n.tr("Localizable", "pageOfWithNumbers", String(describing: p1), String(describing: p2)) - } - - /// Password - internal static let password = L10n.tr("Localizable", "password") - /// Play - internal static let play = L10n.tr("Localizable", "play") - /// Playback settings - internal static let playbackSettings = L10n.tr("Localizable", "playbackSettings") - /// Playback Speed - internal static let playbackSpeed = L10n.tr("Localizable", "playbackSpeed") - /// Play Next - internal static let playNext = L10n.tr("Localizable", "playNext") - /// Reset - internal static let reset = L10n.tr("Localizable", "reset") - /// Search… - internal static let search = L10n.tr("Localizable", "search") - /// S%1$@:E%2$@ - internal static func seasonAndEpisode(_ p1: Any, _ p2: Any) -> String { - L10n.tr("Localizable", "seasonAndEpisode", String(describing: p1), String(describing: p2)) - } - - /// Seasons - internal static let seasons = L10n.tr("Localizable", "seasons") - /// See All - internal static let seeAll = L10n.tr("Localizable", "seeAll") - /// Select Cast Destination - internal static let selectCastDestination = L10n.tr("Localizable", "selectCastDestination") - /// Server %s already exists. Add new URL? - internal static func serverAlreadyExistsPrompt(_ p1: UnsafePointer) -> String { - L10n.tr("Localizable", "serverAlreadyExistsPrompt", p1) - } - - /// Server Information - internal static let serverInformation = L10n.tr("Localizable", "serverInformation") - /// Server URL - internal static let serverURL = L10n.tr("Localizable", "serverURL") - /// Signed in as %@ - internal static func signedInAsWithString(_ p1: Any) -> String { - L10n.tr("Localizable", "signedInAsWithString", String(describing: p1)) - } - - /// Sort by - internal static let sortBy = L10n.tr("Localizable", "sortBy") - /// STUDIO - internal static let studio = L10n.tr("Localizable", "studio") - /// Studios - internal static let studios = L10n.tr("Localizable", "studios") - /// Suggestions - internal static let suggestions = L10n.tr("Localizable", "suggestions") - /// Switch user - internal static let switchUser = L10n.tr("Localizable", "switchUser") - /// System - internal static let system = L10n.tr("Localizable", "system") - /// Tags - internal static let tags = L10n.tr("Localizable", "tags") - /// Try again - internal static let tryAgain = L10n.tr("Localizable", "tryAgain") - /// Unknown Error - internal static let unknownError = L10n.tr("Localizable", "unknownError") - /// Username - internal static let username = L10n.tr("Localizable", "username") - /// Who's watching? - internal static let whosWatching = L10n.tr("Localizable", "WhosWatching") - /// WIP - internal static let wip = L10n.tr("Localizable", "wip") - /// Your Favorites - internal static let yourFavorites = L10n.tr("Localizable", "yourFavorites") + /// About + internal static let about = L10n.tr("Localizable", "about") + /// Accessibility + internal static let accessibility = L10n.tr("Localizable", "accessibility") + /// Add URL + internal static let addURL = L10n.tr("Localizable", "addURL") + /// All Genres + internal static let allGenres = L10n.tr("Localizable", "allGenres") + /// All Media + internal static let allMedia = L10n.tr("Localizable", "allMedia") + /// Appearance + internal static let appearance = L10n.tr("Localizable", "appearance") + /// Apply + internal static let apply = L10n.tr("Localizable", "apply") + /// Audio + internal static let audio = L10n.tr("Localizable", "audio") + /// Audio & Captions + internal static let audioAndCaptions = L10n.tr("Localizable", "audioAndCaptions") + /// Audio Track + internal static let audioTrack = L10n.tr("Localizable", "audioTrack") + /// Auto Play + internal static let autoPlay = L10n.tr("Localizable", "autoPlay") + /// Back + internal static let back = L10n.tr("Localizable", "back") + /// Cancel + internal static let cancel = L10n.tr("Localizable", "cancel") + /// Cannot connect to host + internal static let cannotConnectToHost = L10n.tr("Localizable", "cannotConnectToHost") + /// CAST + internal static let cast = L10n.tr("Localizable", "cast") + /// Cast & Crew + internal static let castAndCrew = L10n.tr("Localizable", "castAndCrew") + /// Change Server + internal static let changeServer = L10n.tr("Localizable", "changeServer") + /// Channels + internal static let channels = L10n.tr("Localizable", "channels") + /// Cinematic Views + internal static let cinematicViews = L10n.tr("Localizable", "cinematicViews") + /// Closed Captions + internal static let closedCaptions = L10n.tr("Localizable", "closedCaptions") + /// Compact + internal static let compact = L10n.tr("Localizable", "compact") + /// Confirm Close + internal static let confirmClose = L10n.tr("Localizable", "confirmClose") + /// Connect + internal static let connect = L10n.tr("Localizable", "connect") + /// Connect Manually + internal static let connectManually = L10n.tr("Localizable", "connectManually") + /// Connect to Jellyfin + internal static let connectToJellyfin = L10n.tr("Localizable", "connectToJellyfin") + /// Connect to a Jellyfin server + internal static let connectToJellyfinServer = L10n.tr("Localizable", "connectToJellyfinServer") + /// Connect to a Jellyfin server to get started + internal static let connectToJellyfinServerStart = L10n.tr("Localizable", "connectToJellyfinServerStart") + /// Connect to Server + internal static let connectToServer = L10n.tr("Localizable", "connectToServer") + /// Containers + internal static let containers = L10n.tr("Localizable", "containers") + /// Continue + internal static let `continue` = L10n.tr("Localizable", "continue") + /// Continue Watching + internal static let continueWatching = L10n.tr("Localizable", "continueWatching") + /// Dark + internal static let dark = L10n.tr("Localizable", "dark") + /// Default Scheme + internal static let defaultScheme = L10n.tr("Localizable", "defaultScheme") + /// DIRECTOR + internal static let director = L10n.tr("Localizable", "director") + /// Discovered Servers + internal static let discoveredServers = L10n.tr("Localizable", "discoveredServers") + /// Display order + internal static let displayOrder = L10n.tr("Localizable", "displayOrder") + /// Edit Jump Lengths + internal static let editJumpLengths = L10n.tr("Localizable", "editJumpLengths") + /// Empty Next Up + internal static let emptyNextUp = L10n.tr("Localizable", "emptyNextUp") + /// Episodes + internal static let episodes = L10n.tr("Localizable", "episodes") + /// Error + internal static let error = L10n.tr("Localizable", "error") + /// Existing Server + internal static let existingServer = L10n.tr("Localizable", "existingServer") + /// Existing User + internal static let existingUser = L10n.tr("Localizable", "existingUser") + /// Experimental + internal static let experimental = L10n.tr("Localizable", "experimental") + /// Favorites + internal static let favorites = L10n.tr("Localizable", "favorites") + /// Filter Results + internal static let filterResults = L10n.tr("Localizable", "filterResults") + /// Filters + internal static let filters = L10n.tr("Localizable", "filters") + /// Genres + internal static let genres = L10n.tr("Localizable", "genres") + /// Home + internal static let home = L10n.tr("Localizable", "home") + /// Information + internal static let information = L10n.tr("Localizable", "information") + /// Items + internal static let items = L10n.tr("Localizable", "items") + /// Jump Backward Length + internal static let jumpBackwardLength = L10n.tr("Localizable", "jumpBackwardLength") + /// Jump Forward Length + internal static let jumpForwardLength = L10n.tr("Localizable", "jumpForwardLength") + /// Jump Gestures Enabled + internal static let jumpGesturesEnabled = L10n.tr("Localizable", "jumpGesturesEnabled") + /// %s seconds + internal static func jumpLengthSeconds(_ p1: UnsafePointer) -> String { + return L10n.tr("Localizable", "jumpLengthSeconds", p1) + } + /// Larger + internal static let larger = L10n.tr("Localizable", "larger") + /// Largest + internal static let largest = L10n.tr("Localizable", "largest") + /// Latest %@ + internal static func latestWithString(_ p1: Any) -> String { + return L10n.tr("Localizable", "latestWithString", String(describing: p1)) + } + /// Library + internal static let library = L10n.tr("Localizable", "library") + /// Light + internal static let light = L10n.tr("Localizable", "light") + /// Loading + internal static let loading = L10n.tr("Localizable", "loading") + /// Local Servers + internal static let localServers = L10n.tr("Localizable", "localServers") + /// Login + internal static let login = L10n.tr("Localizable", "login") + /// Login to %@ + internal static func loginToWithString(_ p1: Any) -> String { + return L10n.tr("Localizable", "loginToWithString", String(describing: p1)) + } + /// Media + internal static let media = L10n.tr("Localizable", "media") + /// More Like This + internal static let moreLikeThis = L10n.tr("Localizable", "moreLikeThis") + /// Movies + internal static let movies = L10n.tr("Localizable", "movies") + /// %d users + internal static func multipleUsers(_ p1: Int) -> String { + return L10n.tr("Localizable", "multipleUsers", p1) + } + /// Name + internal static let name = L10n.tr("Localizable", "name") + /// Networking + internal static let networking = L10n.tr("Localizable", "networking") + /// Network timed out + internal static let networkTimedOut = L10n.tr("Localizable", "networkTimedOut") + /// Next + internal static let next = L10n.tr("Localizable", "next") + /// Next Up + internal static let nextUp = L10n.tr("Localizable", "nextUp") + /// No Cast devices found.. + internal static let noCastdevicesfound = L10n.tr("Localizable", "noCastdevicesfound") + /// No Codec + internal static let noCodec = L10n.tr("Localizable", "noCodec") + /// No episodes available + internal static let noEpisodesAvailable = L10n.tr("Localizable", "noEpisodesAvailable") + /// No local servers found + internal static let noLocalServersFound = L10n.tr("Localizable", "noLocalServersFound") + /// None + internal static let `none` = L10n.tr("Localizable", "none") + /// No overview available + internal static let noOverviewAvailable = L10n.tr("Localizable", "noOverviewAvailable") + /// No results. + internal static let noResults = L10n.tr("Localizable", "noResults") + /// Normal + internal static let normal = L10n.tr("Localizable", "normal") + /// N/A + internal static let notAvailableSlash = L10n.tr("Localizable", "notAvailableSlash") + /// Type: %@ not implemented yet :( + internal static func notImplementedYetWithType(_ p1: Any) -> String { + return L10n.tr("Localizable", "notImplementedYetWithType", String(describing: p1)) + } + /// No title + internal static let noTitle = L10n.tr("Localizable", "noTitle") + /// Ok + internal static let ok = L10n.tr("Localizable", "ok") + /// 1 user + internal static let oneUser = L10n.tr("Localizable", "oneUser") + /// Operating System + internal static let operatingSystem = L10n.tr("Localizable", "operatingSystem") + /// Other + internal static let other = L10n.tr("Localizable", "other") + /// Other User + internal static let otherUser = L10n.tr("Localizable", "otherUser") + /// Overlay + internal static let overlay = L10n.tr("Localizable", "overlay") + /// Overlay Type + internal static let overlayType = L10n.tr("Localizable", "overlayType") + /// Overview + internal static let overview = L10n.tr("Localizable", "overview") + /// Page %1$@ of %2$@ + internal static func pageOfWithNumbers(_ p1: Any, _ p2: Any) -> String { + return L10n.tr("Localizable", "pageOfWithNumbers", String(describing: p1), String(describing: p2)) + } + /// Password + internal static let password = L10n.tr("Localizable", "password") + /// Play + internal static let play = L10n.tr("Localizable", "play") + /// Playback settings + internal static let playbackSettings = L10n.tr("Localizable", "playbackSettings") + /// Playback Speed + internal static let playbackSpeed = L10n.tr("Localizable", "playbackSpeed") + /// Play Next + internal static let playNext = L10n.tr("Localizable", "playNext") + /// Play Next Item + internal static let playNextItem = L10n.tr("Localizable", "playNextItem") + /// Play Previous Item + internal static let playPreviousItem = L10n.tr("Localizable", "playPreviousItem") + /// Present + internal static let present = L10n.tr("Localizable", "present") + /// Press Down for Menu + internal static let pressDownForMenu = L10n.tr("Localizable", "pressDownForMenu") + /// Programs + internal static let programs = L10n.tr("Localizable", "programs") + /// Rated + internal static let rated = L10n.tr("Localizable", "rated") + /// Recently Added + internal static let recentlyAdded = L10n.tr("Localizable", "recentlyAdded") + /// Recommended + internal static let recommended = L10n.tr("Localizable", "recommended") + /// Refresh + internal static let refresh = L10n.tr("Localizable", "refresh") + /// Regular + internal static let regular = L10n.tr("Localizable", "regular") + /// Released + internal static let released = L10n.tr("Localizable", "released") + /// Remove + internal static let remove = L10n.tr("Localizable", "remove") + /// Remove All Users + internal static let removeAllUsers = L10n.tr("Localizable", "removeAllUsers") + /// Reset + internal static let reset = L10n.tr("Localizable", "reset") + /// Reset App Settings + internal static let resetAppSettings = L10n.tr("Localizable", "resetAppSettings") + /// Reset User Settings + internal static let resetUserSettings = L10n.tr("Localizable", "resetUserSettings") + /// Resume 5 Second Offset + internal static let resume5SecondOffset = L10n.tr("Localizable", "resume5SecondOffset") + /// Retry + internal static let retry = L10n.tr("Localizable", "retry") + /// Runtime + internal static let runtime = L10n.tr("Localizable", "runtime") + /// Search + internal static let search = L10n.tr("Localizable", "search") + /// Search… + internal static let searchDots = L10n.tr("Localizable", "searchDots") + /// Searching… + internal static let searchingDots = L10n.tr("Localizable", "searchingDots") + /// Season + internal static let season = L10n.tr("Localizable", "season") + /// S%1$@:E%2$@ + internal static func seasonAndEpisode(_ p1: Any, _ p2: Any) -> String { + return L10n.tr("Localizable", "seasonAndEpisode", String(describing: p1), String(describing: p2)) + } + /// Seasons + internal static let seasons = L10n.tr("Localizable", "seasons") + /// See All + internal static let seeAll = L10n.tr("Localizable", "seeAll") + /// See More + internal static let seeMore = L10n.tr("Localizable", "seeMore") + /// Select Cast Destination + internal static let selectCastDestination = L10n.tr("Localizable", "selectCastDestination") + /// Series + internal static let series = L10n.tr("Localizable", "series") + /// Server + internal static let server = L10n.tr("Localizable", "server") + /// Server %s is already connected + internal static func serverAlreadyConnected(_ p1: UnsafePointer) -> String { + return L10n.tr("Localizable", "serverAlreadyConnected", p1) + } + /// Server %s already exists. Add new URL? + internal static func serverAlreadyExistsPrompt(_ p1: UnsafePointer) -> String { + return L10n.tr("Localizable", "serverAlreadyExistsPrompt", p1) + } + /// Server Details + internal static let serverDetails = L10n.tr("Localizable", "serverDetails") + /// Server Information + internal static let serverInformation = L10n.tr("Localizable", "serverInformation") + /// Servers + internal static let servers = L10n.tr("Localizable", "servers") + /// Server URL + internal static let serverURL = L10n.tr("Localizable", "serverURL") + /// Settings + internal static let settings = L10n.tr("Localizable", "settings") + /// Show Cast & Crew + internal static let showCastAndCrew = L10n.tr("Localizable", "showCastAndCrew") + /// Show Poster Labels + internal static let showPosterLabels = L10n.tr("Localizable", "showPosterLabels") + /// Signed in as %@ + internal static func signedInAsWithString(_ p1: Any) -> String { + return L10n.tr("Localizable", "signedInAsWithString", String(describing: p1)) + } + /// Sign In + internal static let signIn = L10n.tr("Localizable", "signIn") + /// Sign in to get started + internal static let signInGetStarted = L10n.tr("Localizable", "signInGetStarted") + /// Sign In to %s + internal static func signInToServer(_ p1: UnsafePointer) -> String { + return L10n.tr("Localizable", "signInToServer", p1) + } + /// Smaller + internal static let smaller = L10n.tr("Localizable", "smaller") + /// Smallest + internal static let smallest = L10n.tr("Localizable", "smallest") + /// Sort by + internal static let sortBy = L10n.tr("Localizable", "sortBy") + /// STUDIO + internal static let studio = L10n.tr("Localizable", "studio") + /// Studios + internal static let studios = L10n.tr("Localizable", "studios") + /// Subtitles + internal static let subtitles = L10n.tr("Localizable", "subtitles") + /// Subtitle Size + internal static let subtitleSize = L10n.tr("Localizable", "subtitleSize") + /// Suggestions + internal static let suggestions = L10n.tr("Localizable", "suggestions") + /// Switch User + internal static let switchUser = L10n.tr("Localizable", "switchUser") + /// System + internal static let system = L10n.tr("Localizable", "system") + /// Tags + internal static let tags = L10n.tr("Localizable", "tags") + /// Try again + internal static let tryAgain = L10n.tr("Localizable", "tryAgain") + /// TV Shows + internal static let tvShows = L10n.tr("Localizable", "tvShows") + /// Unable to connect to server + internal static let unableToConnectServer = L10n.tr("Localizable", "unableToConnectServer") + /// Unauthorized + internal static let unauthorized = L10n.tr("Localizable", "unauthorized") + /// Unauthorized user + internal static let unauthorizedUser = L10n.tr("Localizable", "unauthorizedUser") + /// Unknown + internal static let unknown = L10n.tr("Localizable", "unknown") + /// Unknown Error + internal static let unknownError = L10n.tr("Localizable", "unknownError") + /// URL + internal static let url = L10n.tr("Localizable", "url") + /// User + internal static let user = L10n.tr("Localizable", "user") + /// User %s is already signed in + internal static func userAlreadySignedIn(_ p1: UnsafePointer) -> String { + return L10n.tr("Localizable", "userAlreadySignedIn", p1) + } + /// Username + internal static let username = L10n.tr("Localizable", "username") + /// Version + internal static let version = L10n.tr("Localizable", "version") + /// Video Player + internal static let videoPlayer = L10n.tr("Localizable", "videoPlayer") + /// Who's watching? + internal static let whosWatching = L10n.tr("Localizable", "WhosWatching") + /// WIP + internal static let wip = L10n.tr("Localizable", "wip") + /// Your Favorites + internal static let yourFavorites = L10n.tr("Localizable", "yourFavorites") } - // swiftlint:enable explicit_type_interface function_parameter_count identifier_name line_length // swiftlint:enable nesting type_body_length type_name vertical_whitespace_opening_braces // MARK: - Implementation Details extension L10n { - private static func tr(_ table: String, _ key: String, _ args: CVarArg...) -> String { - let format = BundleToken.bundle.localizedString(forKey: key, value: nil, table: table) - return String(format: format, locale: Locale.current, arguments: args) - } + private static func tr(_ table: String, _ key: String, _ args: CVarArg...) -> String { + let format = BundleToken.bundle.localizedString(forKey: key, value: nil, table: table) + return String(format: format, locale: Locale.current, arguments: args) + } } // swiftlint:disable convenience_type private final class BundleToken { - static let bundle: Bundle = { - #if SWIFT_PACKAGE - return Bundle.module - #else - return Bundle(for: BundleToken.self) - #endif - }() + static let bundle: Bundle = { + #if SWIFT_PACKAGE + return Bundle.module + #else + return Bundle(for: BundleToken.self) + #endif + }() } - // swiftlint:enable convenience_type diff --git a/Shared/Objects/DetailItem.swift b/Shared/Objects/DetailItem.swift deleted file mode 100644 index 7e1c0b6a..00000000 --- a/Shared/Objects/DetailItem.swift +++ /dev/null @@ -1,23 +0,0 @@ -// -// Swiftfin is subject to the terms of the Mozilla Public -// License, v2.0. If a copy of the MPL was not distributed with this -// file, you can obtain one at https://mozilla.org/MPL/2.0/. -// -// Copyright (c) 2022 Jellyfin & Jellyfin Contributors -// - -import Foundation -import JellyfinAPI - -enum DetailItemType: String { - case movie = "Movie" - case season = "Season" - case series = "Series" - case episode = "Episode" -} - -struct DetailItem { - - let baseItem: BaseItemDto - let type: DetailItemType -} diff --git a/Shared/Objects/OverlayType.swift b/Shared/Objects/OverlayType.swift index eacbe607..f0b2afab 100644 --- a/Shared/Objects/OverlayType.swift +++ b/Shared/Objects/OverlayType.swift @@ -16,9 +16,9 @@ enum OverlayType: String, CaseIterable, Defaults.Serializable { var label: String { switch self { case .normal: - return "Normal" + return L10n.normal case .compact: - return "Compact" + return L10n.compact } } } diff --git a/Shared/Objects/SubtitleSize.swift b/Shared/Objects/SubtitleSize.swift index bd583aef..8d457065 100644 --- a/Shared/Objects/SubtitleSize.swift +++ b/Shared/Objects/SubtitleSize.swift @@ -22,15 +22,15 @@ extension SubtitleSize { var label: String { switch self { case .smallest: - return "Smallest" + return L10n.smallest case .smaller: - return "Smaller" + return L10n.smaller case .regular: - return "Regular" + return L10n.regular case .larger: - return "Larger" + return L10n.larger case .largest: - return "Largest" + return L10n.largest } } } diff --git a/Shared/Objects/VideoPlayerJumpLength.swift b/Shared/Objects/VideoPlayerJumpLength.swift index 5a701d03..9bb56561 100644 --- a/Shared/Objects/VideoPlayerJumpLength.swift +++ b/Shared/Objects/VideoPlayerJumpLength.swift @@ -16,7 +16,7 @@ enum VideoPlayerJumpLength: Int32, CaseIterable, Defaults.Serializable { case five = 5 var label: String { - "\(self.rawValue) seconds" + L10n.jumpLengthSeconds("\(self.rawValue)") } var shortLabel: String { diff --git a/Shared/SwiftfinStore/SwiftfinStore.swift b/Shared/SwiftfinStore/SwiftfinStore.swift index 9629c1da..99aaa8af 100644 --- a/Shared/SwiftfinStore/SwiftfinStore.swift +++ b/Shared/SwiftfinStore/SwiftfinStore.swift @@ -198,18 +198,18 @@ extension SwiftfinStore.Errors: LocalizedError { var title: String { switch self { case .existingServer: - return "Existing Server" + return L10n.existingServer case .existingUser: - return "Existing User" + return L10n.existingUser } } var errorDescription: String? { switch self { case let .existingServer(server): - return "Server \(server.name) already exists with same server ID" + return L10n.serverAlreadyConnected(server.name) case let .existingUser(user): - return "User \(user.username) already exists with same user ID" + return L10n.userAlreadySignedIn(user.username) } } } diff --git a/Shared/ViewModels/ConnectToServerViewModel.swift b/Shared/ViewModels/ConnectToServerViewModel.swift index 53ac9164..1fcaa00f 100644 --- a/Shared/ViewModels/ConnectToServerViewModel.swift +++ b/Shared/ViewModels/ConnectToServerViewModel.swift @@ -40,7 +40,7 @@ final class ConnectToServerViewModel: ViewModel { if errorMessage?.code != ErrorMessage.noShowErrorCode { message.append(contentsOf: "\(errorMessage?.code ?? ErrorMessage.noShowErrorCode)\n") } - message.append(contentsOf: "\(errorMessage?.title ?? "Unkown Error")") + message.append(contentsOf: "\(errorMessage?.title ?? L10n.unknownError)") return message } @@ -70,12 +70,12 @@ final class ConnectToServerViewModel: ViewModel { self.addServerURIPayload = AddServerURIPayload(server: server, uri: uri) self.backAddServerURIPayload = AddServerURIPayload(server: server, uri: uri) default: - self.handleAPIRequestError(displayMessage: "Unable to connect to server.", logLevel: .critical, + self.handleAPIRequestError(displayMessage: L10n.unableToConnectServer, logLevel: .critical, tag: "connectToServer", completion: completion) } default: - self.handleAPIRequestError(displayMessage: "Unable to connect to server.", logLevel: .critical, + self.handleAPIRequestError(displayMessage: L10n.unableToConnectServer, logLevel: .critical, tag: "connectToServer", completion: completion) } @@ -106,12 +106,12 @@ final class ConnectToServerViewModel: ViewModel { func addURIToServer(addServerURIPayload: AddServerURIPayload) { SessionManager.main.addURIToServer(server: addServerURIPayload.server, uri: addServerURIPayload.uri) .sink { completion in - self.handleAPIRequestError(displayMessage: "Unable to connect to server.", logLevel: .critical, tag: "connectToServer", + self.handleAPIRequestError(displayMessage: L10n.unableToConnectServer, logLevel: .critical, tag: "connectToServer", completion: completion) } receiveValue: { server in SessionManager.main.setServerCurrentURI(server: server, uri: addServerURIPayload.uri) .sink { completion in - self.handleAPIRequestError(displayMessage: "Unable to connect to server.", logLevel: .critical, + self.handleAPIRequestError(displayMessage: L10n.unableToConnectServer, logLevel: .critical, tag: "connectToServer", completion: completion) } receiveValue: { _ in diff --git a/Shared/ViewModels/ItemViewModel/SeriesItemViewModel.swift b/Shared/ViewModels/ItemViewModel/SeriesItemViewModel.swift index a8f0e4ef..239b5edb 100644 --- a/Shared/ViewModels/ItemViewModel/SeriesItemViewModel.swift +++ b/Shared/ViewModels/ItemViewModel/SeriesItemViewModel.swift @@ -64,7 +64,7 @@ final class SeriesItemViewModel: ItemViewModel { endYear = dateFormatter.string(from: item.endDate!) } - return "\(startYear ?? "Unknown") - \(endYear ?? "Present")" + return "\(startYear ?? L10n.unknown) - \(endYear ?? L10n.present)" } private func requestSeasons() { diff --git a/Shared/ViewModels/ServerListViewModel.swift b/Shared/ViewModels/ServerListViewModel.swift index d1d8d55e..eb0f1184 100644 --- a/Shared/ViewModels/ServerListViewModel.swift +++ b/Shared/ViewModels/ServerListViewModel.swift @@ -30,9 +30,9 @@ class ServerListViewModel: ObservableObject { func userTextFor(server: SwiftfinStore.State.Server) -> String { if server.userIDs.count == 1 { - return "1 user" + return L10n.oneUser } else { - return "\(server.userIDs.count) users" + return L10n.multipleUsers(server.userIDs.count) } } diff --git a/Shared/ViewModels/UserSignInViewModel.swift b/Shared/ViewModels/UserSignInViewModel.swift index cd2fa830..a7d35da9 100644 --- a/Shared/ViewModels/UserSignInViewModel.swift +++ b/Shared/ViewModels/UserSignInViewModel.swift @@ -36,7 +36,7 @@ final class UserSignInViewModel: ViewModel { SessionManager.main.loginUser(server: server, username: username, password: password) .trackActivity(loading) .sink { completion in - self.handleAPIRequestError(displayMessage: "Unable to connect to server.", logLevel: .critical, tag: "login", + self.handleAPIRequestError(displayMessage: L10n.unableToConnectServer, logLevel: .critical, tag: "login", completion: completion) } receiveValue: { _ in } diff --git a/Shared/Views/LiveTVChannelItemElement.swift b/Shared/Views/LiveTVChannelItemElement.swift index 35fdd41d..b9f63dd8 100644 --- a/Shared/Views/LiveTVChannelItemElement.swift +++ b/Shared/Views/LiveTVChannelItemElement.swift @@ -36,7 +36,7 @@ struct LiveTVChannelItemElement: View { .font(.footnote) .lineLimit(1) .frame(alignment: .center) - Text(program?.name ?? "N/A") + Text(program?.name ?? L10n.notAvailableSlash) .font(.body) .lineLimit(1) .foregroundColor(.green) diff --git a/Shared/Views/SearchBarView.swift b/Shared/Views/SearchBarView.swift index f33391c9..4b848372 100644 --- a/Shared/Views/SearchBarView.swift +++ b/Shared/Views/SearchBarView.swift @@ -17,7 +17,7 @@ struct SearchBar: View { var body: some View { HStack(spacing: 8) { - TextField(L10n.search, text: $text) + TextField(L10n.searchDots, text: $text) .padding(8) .padding(.horizontal, 16) #if os(iOS) diff --git a/Swiftfin tvOS/Components/EpisodesRowView.swift b/Swiftfin tvOS/Components/EpisodesRowView.swift index c5696110..a83567f7 100644 --- a/Swiftfin tvOS/Components/EpisodesRowView.swift +++ b/Swiftfin tvOS/Components/EpisodesRowView.swift @@ -19,7 +19,7 @@ struct EpisodesRowView: View { var body: some View { VStack(alignment: .leading) { - Text(viewModel.selectedSeason?.name ?? "Episodes") + Text(viewModel.selectedSeason?.name ?? L10n.episodes) .font(.title3) .padding(.horizontal, 50) @@ -67,7 +67,7 @@ struct EpisodesRowView: View { Text("--") .font(.caption) .foregroundColor(.secondary) - Text("No episodes available") + L10n.noEpisodesAvailable.text .font(.footnote) .padding(.bottom, 1) } diff --git a/Swiftfin tvOS/Components/HomeCinematicView/CinematicNextUpCardView.swift b/Swiftfin tvOS/Components/HomeCinematicView/CinematicNextUpCardView.swift index 13ef8d01..aa3c37a5 100644 --- a/Swiftfin tvOS/Components/HomeCinematicView/CinematicNextUpCardView.swift +++ b/Swiftfin tvOS/Components/HomeCinematicView/CinematicNextUpCardView.swift @@ -39,7 +39,7 @@ struct CinematicNextUpCardView: View { if showOverlay { VStack(alignment: .leading, spacing: 0) { - Text("Next") + L10n.next.text .font(.subheadline) .padding(.vertical, 5) .padding(.leading, 10) diff --git a/Swiftfin tvOS/Components/ItemDetailsView.swift b/Swiftfin tvOS/Components/ItemDetailsView.swift index d53ed148..f6cee712 100644 --- a/Swiftfin tvOS/Components/ItemDetailsView.swift +++ b/Swiftfin tvOS/Components/ItemDetailsView.swift @@ -24,7 +24,7 @@ struct ItemDetailsView: View { HStack(alignment: .top) { VStack(alignment: .leading, spacing: 20) { - Text("Information") + L10n.information.text .font(.title3) .padding(.bottom, 5) @@ -36,7 +36,7 @@ struct ItemDetailsView: View { Spacer() VStack(alignment: .leading, spacing: 20) { - Text("Media") + L10n.media.text .font(.title3) .padding(.bottom, 5) diff --git a/Swiftfin tvOS/Components/SingleSeasonEpisodesRowView.swift b/Swiftfin tvOS/Components/SingleSeasonEpisodesRowView.swift index 1d06169c..b2bb1c11 100644 --- a/Swiftfin tvOS/Components/SingleSeasonEpisodesRowView.swift +++ b/Swiftfin tvOS/Components/SingleSeasonEpisodesRowView.swift @@ -19,7 +19,7 @@ struct SingleSeasonEpisodesRowView: View { var body: some View { VStack(alignment: .leading) { - Text("Episodes") + L10n.episodes.text .font(.title3) .padding(.horizontal, 50) @@ -66,7 +66,7 @@ struct SingleSeasonEpisodesRowView: View { Text("--") .font(.caption) .foregroundColor(.secondary) - Text("No episodes available") + L10n.noEpisodesAvailable.text .font(.footnote) .padding(.bottom, 1) } diff --git a/Swiftfin tvOS/Views/BasicAppSettingsView.swift b/Swiftfin tvOS/Views/BasicAppSettingsView.swift index 1c988e24..2b3745c5 100644 --- a/Swiftfin tvOS/Views/BasicAppSettingsView.swift +++ b/Swiftfin tvOS/Views/BasicAppSettingsView.swift @@ -48,6 +48,6 @@ struct BasicAppSettingsView: View { L10n.reset.text } }) - .navigationTitle("Settings") + .navigationTitle(L10n.settings) } } diff --git a/Swiftfin tvOS/Views/ConnectToServerView.swift b/Swiftfin tvOS/Views/ConnectToServerView.swift index 7a1319a9..9c81da0b 100644 --- a/Swiftfin tvOS/Views/ConnectToServerView.swift +++ b/Swiftfin tvOS/Views/ConnectToServerView.swift @@ -46,7 +46,7 @@ struct ConnectToServerView: View { } .disabled(viewModel.isLoading || uri.isEmpty) } header: { - Text("Connect to a Jellyfin server") + L10n.connectToJellyfinServer.text } Section(header: L10n.localServers.text) { @@ -77,7 +77,7 @@ struct ConnectToServerView: View { } .alert(item: $viewModel.errorMessage) { _ in Alert(title: Text(viewModel.alertTitle), - message: Text(viewModel.errorMessage?.displayMessage ?? "Unknown Error"), + message: Text(viewModel.errorMessage?.displayMessage ?? L10n.unknownError), dismissButton: .cancel()) } .navigationTitle(L10n.connect) diff --git a/Swiftfin tvOS/Views/HomeView.swift b/Swiftfin tvOS/Views/HomeView.swift index 435eedbc..787ecfc7 100644 --- a/Swiftfin tvOS/Views/HomeView.swift +++ b/Swiftfin tvOS/Views/HomeView.swift @@ -33,7 +33,7 @@ struct HomeView: View { if viewModel.resumeItems.isEmpty { HomeCinematicView(items: viewModel.latestAddedItems.map { .init(item: $0, type: .plain) }, - forcedItemSubtitle: "Recently Added") + forcedItemSubtitle: L10n.recentlyAdded) if !viewModel.nextUpItems.isEmpty { NextUpView(items: viewModel.nextUpItems) @@ -47,7 +47,7 @@ struct HomeView: View { .focusSection() } - PortraitItemsRowView(rowTitle: "Recently Added", + PortraitItemsRowView(rowTitle: L10n.recentlyAdded, items: viewModel.latestAddedItems, showItemTitles: showPosterLabels) { item in homeRouter.route(to: \.modalItem, item) @@ -67,7 +67,7 @@ struct HomeView: View { Button { viewModel.refresh() } label: { - Text("Refresh") + L10n.refresh.text } Spacer() diff --git a/Swiftfin tvOS/Views/ItemView/CinematicItemView/CinematicCollectionItemView.swift b/Swiftfin tvOS/Views/ItemView/CinematicItemView/CinematicCollectionItemView.swift index 2fe6275f..e7c30b24 100644 --- a/Swiftfin tvOS/Views/ItemView/CinematicItemView/CinematicCollectionItemView.swift +++ b/Swiftfin tvOS/Views/ItemView/CinematicItemView/CinematicCollectionItemView.swift @@ -46,13 +46,13 @@ struct CinematicCollectionItemView: View { CinematicItemAboutView(viewModel: viewModel) - PortraitItemsRowView(rowTitle: "Items", + PortraitItemsRowView(rowTitle: L10n.items, items: viewModel.collectionItems) { item in itemRouter.route(to: \.item, item) } if !viewModel.similarItems.isEmpty { - PortraitItemsRowView(rowTitle: "Recommended", + PortraitItemsRowView(rowTitle: L10n.recommended, items: viewModel.similarItems, showItemTitles: showPosterLabels) { item in itemRouter.route(to: \.item, item) diff --git a/Swiftfin tvOS/Views/ItemView/CinematicItemView/CinematicEpisodeItemView.swift b/Swiftfin tvOS/Views/ItemView/CinematicItemView/CinematicEpisodeItemView.swift index 5fec9500..ad53b7cf 100644 --- a/Swiftfin tvOS/Views/ItemView/CinematicItemView/CinematicEpisodeItemView.swift +++ b/Swiftfin tvOS/Views/ItemView/CinematicItemView/CinematicEpisodeItemView.swift @@ -60,14 +60,14 @@ struct CinematicEpisodeItemView: View { .focusSection() if let seriesItem = viewModel.series { - PortraitItemsRowView(rowTitle: "Series", + PortraitItemsRowView(rowTitle: L10n.series, items: [seriesItem]) { seriesItem in itemRouter.route(to: \.item, seriesItem) } } if !viewModel.similarItems.isEmpty { - PortraitItemsRowView(rowTitle: "Recommended", + PortraitItemsRowView(rowTitle: L10n.recommended, items: viewModel.similarItems, showItemTitles: showPosterLabels) { item in itemRouter.route(to: \.item, item) diff --git a/Swiftfin tvOS/Views/ItemView/CinematicItemView/CinematicItemAboutView.swift b/Swiftfin tvOS/Views/ItemView/CinematicItemView/CinematicItemAboutView.swift index 6e20b039..15c7ac25 100644 --- a/Swiftfin tvOS/Views/ItemView/CinematicItemView/CinematicItemAboutView.swift +++ b/Swiftfin tvOS/Views/ItemView/CinematicItemView/CinematicItemAboutView.swift @@ -26,10 +26,10 @@ struct CinematicItemAboutView: View { .frame(height: 385.5) VStack(alignment: .leading) { - Text("About") + L10n.about.text .font(.title3) - Text(viewModel.item.overview ?? "No details available") + Text(viewModel.item.overview ?? L10n.noOverviewAvailable) .padding(.top, 2) .lineLimit(7) } diff --git a/Swiftfin tvOS/Views/ItemView/CinematicItemView/CinematicMovieItemView.swift b/Swiftfin tvOS/Views/ItemView/CinematicItemView/CinematicMovieItemView.swift index 445822dd..8b4baef5 100644 --- a/Swiftfin tvOS/Views/ItemView/CinematicItemView/CinematicMovieItemView.swift +++ b/Swiftfin tvOS/Views/ItemView/CinematicItemView/CinematicMovieItemView.swift @@ -47,7 +47,7 @@ struct CinematicMovieItemView: View { CinematicItemAboutView(viewModel: viewModel) if !viewModel.similarItems.isEmpty { - PortraitItemsRowView(rowTitle: "Recommended", + PortraitItemsRowView(rowTitle: L10n.recommended, items: viewModel.similarItems, showItemTitles: showPosterLabels) { item in itemRouter.route(to: \.item, item) diff --git a/Swiftfin tvOS/Views/ItemView/CinematicItemView/CinematicSeasonItemView.swift b/Swiftfin tvOS/Views/ItemView/CinematicItemView/CinematicSeasonItemView.swift index a3c4190a..2af96825 100644 --- a/Swiftfin tvOS/Views/ItemView/CinematicItemView/CinematicSeasonItemView.swift +++ b/Swiftfin tvOS/Views/ItemView/CinematicItemView/CinematicSeasonItemView.swift @@ -56,14 +56,14 @@ struct CinematicSeasonItemView: View { SingleSeasonEpisodesRowView(viewModel: SingleSeasonEpisodesRowViewModel(seasonItemViewModel: viewModel)) if let seriesItem = viewModel.seriesItem { - PortraitItemsRowView(rowTitle: "Series", + PortraitItemsRowView(rowTitle: L10n.series, items: [seriesItem]) { seriesItem in itemRouter.route(to: \.item, seriesItem) } } if !viewModel.similarItems.isEmpty { - PortraitItemsRowView(rowTitle: "Recommended", + PortraitItemsRowView(rowTitle: L10n.recommended, items: viewModel.similarItems, showItemTitles: showPosterLabels) { item in itemRouter.route(to: \.item, item) diff --git a/Swiftfin tvOS/Views/ItemView/CinematicItemView/CinematicSeriesItemView.swift b/Swiftfin tvOS/Views/ItemView/CinematicItemView/CinematicSeriesItemView.swift index 6ce1edbd..d3a057d2 100644 --- a/Swiftfin tvOS/Views/ItemView/CinematicItemView/CinematicSeriesItemView.swift +++ b/Swiftfin tvOS/Views/ItemView/CinematicItemView/CinematicSeriesItemView.swift @@ -45,14 +45,14 @@ struct CinematicSeriesItemView: View { CinematicItemAboutView(viewModel: viewModel) - PortraitItemsRowView(rowTitle: "Seasons", + PortraitItemsRowView(rowTitle: L10n.seasons, items: viewModel.seasons, showItemTitles: showPosterLabels) { season in itemRouter.route(to: \.item, season) } if !viewModel.similarItems.isEmpty { - PortraitItemsRowView(rowTitle: "Recommended", + PortraitItemsRowView(rowTitle: L10n.recommended, items: viewModel.similarItems, showItemTitles: showPosterLabels) { item in itemRouter.route(to: \.item, item) diff --git a/Swiftfin tvOS/Views/LibrarySearchView.swift b/Swiftfin tvOS/Views/LibrarySearchView.swift index 4edb744a..b2d11c29 100644 --- a/Swiftfin tvOS/Views/LibrarySearchView.swift +++ b/Swiftfin tvOS/Views/LibrarySearchView.swift @@ -42,7 +42,7 @@ struct LibrarySearchView: View { .onChange(of: searchQuery) { query in viewModel.searchQuerySubject.send(query) } - .navigationBarTitle("Search") + .navigationBarTitle(L10n.search) } var suggestionsListView: some View { diff --git a/Swiftfin tvOS/Views/LibraryView.swift b/Swiftfin tvOS/Views/LibraryView.swift index d65cb25d..0fcd6240 100644 --- a/Swiftfin tvOS/Views/LibraryView.swift +++ b/Swiftfin tvOS/Views/LibraryView.swift @@ -85,7 +85,7 @@ struct LibraryView: View { VStack { L10n.noResults.text Button {} label: { - Text("Reload") + L10n.refresh.text } } } diff --git a/Swiftfin tvOS/Views/MovieLibrariesView.swift b/Swiftfin tvOS/Views/MovieLibrariesView.swift index 3e906b68..01faf827 100644 --- a/Swiftfin tvOS/Views/MovieLibrariesView.swift +++ b/Swiftfin tvOS/Views/MovieLibrariesView.swift @@ -73,7 +73,7 @@ struct MovieLibrariesView: View { Button { print("movieLibraries reload") } label: { - Text("Reload") + L10n.refresh.text } } } diff --git a/Swiftfin tvOS/Views/ServerDetailView.swift b/Swiftfin tvOS/Views/ServerDetailView.swift index df096643..d8049654 100644 --- a/Swiftfin tvOS/Views/ServerDetailView.swift +++ b/Swiftfin tvOS/Views/ServerDetailView.swift @@ -15,9 +15,9 @@ struct ServerDetailView: View { var body: some View { Form { - Section(header: Text("Server Details")) { + Section(header: L10n.serverDetails.text) { HStack { - Text("Name") + L10n.name.text Spacer() Text(SessionManager.main.currentLogin.server.name) .foregroundColor(.secondary) @@ -25,21 +25,21 @@ struct ServerDetailView: View { .focusable() HStack { - Text("URI") + L10n.url.text Spacer() Text(SessionManager.main.currentLogin.server.currentURI) .foregroundColor(.secondary) } HStack { - Text("Version") + L10n.version.text Spacer() Text(SessionManager.main.currentLogin.server.version) .foregroundColor(.secondary) } HStack { - Text("Operating System") + L10n.operatingSystem.text Spacer() Text(SessionManager.main.currentLogin.server.os) .foregroundColor(.secondary) diff --git a/Swiftfin tvOS/Views/ServerListView.swift b/Swiftfin tvOS/Views/ServerListView.swift index 3d8c2dd4..0654b00a 100644 --- a/Swiftfin tvOS/Views/ServerListView.swift +++ b/Swiftfin tvOS/Views/ServerListView.swift @@ -52,7 +52,7 @@ struct ServerListView: View { Button(role: .destructive) { viewModel.remove(server: server) } label: { - Label("Remove", systemImage: "trash") + Label(L10n.remove, systemImage: "trash") } } } @@ -65,7 +65,7 @@ struct ServerListView: View { @ViewBuilder private var noServerView: some View { VStack { - Text("Connect to a Jellyfin server to get started") + L10n.connectToJellyfinServerStart.text .frame(minWidth: 50, maxWidth: 500) .multilineTextAlignment(.center) .font(.body) @@ -109,7 +109,7 @@ struct ServerListView: View { Button { serverListRouter.route(to: \.basicAppSettings) } label: { - Text("Settings") + L10n.settings.text } } } @@ -117,7 +117,7 @@ struct ServerListView: View { var body: some View { innerBody - .navigationTitle("Servers") + .navigationTitle(L10n.servers) .toolbar { ToolbarItemGroup(placement: .navigationBarTrailing) { trailingToolbarContent diff --git a/Swiftfin tvOS/Views/SettingsView/ExperimentalSettingsView.swift b/Swiftfin tvOS/Views/SettingsView/ExperimentalSettingsView.swift index 1ec0351a..39caa9e8 100644 --- a/Swiftfin tvOS/Views/SettingsView/ExperimentalSettingsView.swift +++ b/Swiftfin tvOS/Views/SettingsView/ExperimentalSettingsView.swift @@ -25,7 +25,7 @@ struct ExperimentalSettingsView: View { Toggle("Live TV (Alpha)", isOn: $liveTVAlphaEnabled) } header: { - Text("Experimental") + L10n.experimental.text } } } diff --git a/Swiftfin tvOS/Views/SettingsView/OverlaySettingsView.swift b/Swiftfin tvOS/Views/SettingsView/OverlaySettingsView.swift index 304151c2..d108b0cf 100644 --- a/Swiftfin tvOS/Views/SettingsView/OverlaySettingsView.swift +++ b/Swiftfin tvOS/Views/SettingsView/OverlaySettingsView.swift @@ -20,11 +20,28 @@ struct OverlaySettingsView: View { var body: some View { Form { - Section(header: Text("Overlay")) { + Section(header: L10n.overlay.text) { - Toggle("\(Image(systemName: "chevron.left.circle")) Play Previous Item", isOn: $shouldShowPlayPreviousItem) - Toggle("\(Image(systemName: "chevron.right.circle")) Play Next Item", isOn: $shouldShowPlayNextItem) - Toggle("\(Image(systemName: "play.circle.fill")) Auto Play", isOn: $shouldShowAutoPlay) + Toggle(isOn: $shouldShowPlayPreviousItem) { + HStack { + Image(systemName: "chevron.left.circle") + L10n.playPreviousItem.text + } + } + + Toggle(isOn: $shouldShowPlayNextItem) { + HStack { + Image(systemName: "chevron.right.circle") + L10n.playNextItem.text + } + } + + Toggle(isOn: $shouldShowAutoPlay) { + HStack { + Image(systemName: "play.circle.fill") + L10n.autoPlay.text + } + } } } } diff --git a/Swiftfin tvOS/Views/SettingsView/SettingsView.swift b/Swiftfin tvOS/Views/SettingsView/SettingsView.swift index e2fbd299..6b92689a 100644 --- a/Swiftfin tvOS/Views/SettingsView/SettingsView.swift +++ b/Swiftfin tvOS/Views/SettingsView/SettingsView.swift @@ -51,7 +51,7 @@ struct SettingsView: View { Button {} label: { HStack { - Text("User") + L10n.user.text Spacer() Text(viewModel.user.username) .foregroundColor(.jellyfinPurple) @@ -62,7 +62,7 @@ struct SettingsView: View { settingsRouter.route(to: \.serverDetail) } label: { HStack { - Text("Server") + L10n.server.text .foregroundColor(.primary) Spacer() Text(viewModel.server.name) @@ -76,36 +76,36 @@ struct SettingsView: View { Button { SessionManager.main.logout() } label: { - Text("Switch User") + L10n.switchUser.text .foregroundColor(Color.jellyfinPurple) .font(.callout) } } - Section(header: Text("Video Player")) { - Picker("Jump Forward Length", selection: $jumpForwardLength) { + Section(header: L10n.videoPlayer.text) { + Picker(L10n.jumpForwardLength, selection: $jumpForwardLength) { ForEach(VideoPlayerJumpLength.allCases, id: \.self) { length in Text(length.label).tag(length.rawValue) } } - Picker("Jump Backward Length", selection: $jumpBackwardLength) { + Picker(L10n.jumpBackwardLength, selection: $jumpBackwardLength) { ForEach(VideoPlayerJumpLength.allCases, id: \.self) { length in Text(length.label).tag(length.rawValue) } } - Toggle("Resume 5 Second Offset", isOn: $resumeOffset) + Toggle(L10n.resume5SecondOffset, isOn: $resumeOffset) - Toggle("Press Down for Menu", isOn: $downActionShowsMenu) + Toggle(L10n.pressDownForMenu, isOn: $downActionShowsMenu) - Toggle("Confirm Close", isOn: $confirmClose) + Toggle(L10n.confirmClose, isOn: $confirmClose) Button { settingsRouter.route(to: \.overlaySettings) } label: { HStack { - Text("Overlay") + L10n.overlay.text .foregroundColor(.primary) Spacer() Image(systemName: "chevron.right") @@ -116,7 +116,7 @@ struct SettingsView: View { settingsRouter.route(to: \.experimentalSettings) } label: { HStack { - Text("Experimental") + L10n.experimental.text .foregroundColor(.primary) Spacer() Image(systemName: "chevron.right") @@ -125,15 +125,15 @@ struct SettingsView: View { } Section { - Toggle("Cinematic Views", isOn: $tvOSCinematicViews) + Toggle(L10n.cinematicViews, isOn: $tvOSCinematicViews) } header: { - Text("Appearance") + L10n.appearance.text } Section(header: L10n.accessibility.text) { - Toggle("Show Poster Labels", isOn: $showPosterLabels) + Toggle(L10n.showPosterLabels, isOn: $showPosterLabels) - Picker("Subtitle size", selection: $subtitleSize) { + Picker(L10n.subtitleSize, selection: $subtitleSize) { ForEach(SubtitleSize.allCases, id: \.self) { size in Text(size.label).tag(size.rawValue) } diff --git a/Swiftfin tvOS/Views/TVLibrariesView.swift b/Swiftfin tvOS/Views/TVLibrariesView.swift index ec5f4e9c..abfd7426 100644 --- a/Swiftfin tvOS/Views/TVLibrariesView.swift +++ b/Swiftfin tvOS/Views/TVLibrariesView.swift @@ -73,7 +73,7 @@ struct TVLibrariesView: View { Button { print("tvLibraries reload") } label: { - Text("Reload") + L10n.refresh.text } } } diff --git a/Swiftfin tvOS/Views/UserListView.swift b/Swiftfin tvOS/Views/UserListView.swift index 983035a5..6e5403cb 100644 --- a/Swiftfin tvOS/Views/UserListView.swift +++ b/Swiftfin tvOS/Views/UserListView.swift @@ -39,7 +39,7 @@ struct UserListView: View { Button(role: .destructive) { viewModel.remove(user: user) } label: { - Label("Remove", systemImage: "trash") + Label(L10n.remove, systemImage: "trash") } } } @@ -52,7 +52,7 @@ struct UserListView: View { @ViewBuilder private var noUserView: some View { VStack { - Text("Sign in to get started") + L10n.signInGetStarted.text .frame(minWidth: 50, maxWidth: 500) .multilineTextAlignment(.center) .font(.callout) @@ -60,7 +60,7 @@ struct UserListView: View { Button { userListRouter.route(to: \.userSignIn, viewModel.server) } label: { - Text("Sign in") + L10n.signIn.text .bold() .font(.callout) } diff --git a/Swiftfin tvOS/Views/UserSignInView.swift b/Swiftfin tvOS/Views/UserSignInView.swift index 4caa8717..de874fb3 100644 --- a/Swiftfin tvOS/Views/UserSignInView.swift +++ b/Swiftfin tvOS/Views/UserSignInView.swift @@ -44,14 +44,14 @@ struct UserSignInView: View { .disabled(viewModel.isLoading || username.isEmpty) } header: { - Text("Sign In to \(viewModel.server.name)") + L10n.signInToServer(viewModel.server.name).text } } .alert(item: $viewModel.errorMessage) { _ in Alert(title: Text(viewModel.alertTitle), - message: Text(viewModel.errorMessage?.displayMessage ?? "Unknown Error"), + message: Text(viewModel.errorMessage?.displayMessage ?? L10n.unknownError), dismissButton: .cancel()) } - .navigationTitle("Sign In") + .navigationTitle(L10n.signIn) } } diff --git a/Swiftfin tvOS/Views/VideoPlayer/tvOSOverlay/SmallMenuOverlay.swift b/Swiftfin tvOS/Views/VideoPlayer/tvOSOverlay/SmallMenuOverlay.swift index c754d994..f128656c 100644 --- a/Swiftfin tvOS/Views/VideoPlayer/tvOSOverlay/SmallMenuOverlay.swift +++ b/Swiftfin tvOS/Views/VideoPlayer/tvOSOverlay/SmallMenuOverlay.swift @@ -74,7 +74,7 @@ struct SmallMediaStreamSelectionView: View { if updateFocusedLayer == .subtitles { HStack(spacing: 15) { Image(systemName: "captions.bubble") - Text("Subtitles") + L10n.subtitles.text } .padding() .background(Color.white) @@ -82,7 +82,7 @@ struct SmallMediaStreamSelectionView: View { } else { HStack(spacing: 15) { Image(systemName: "captions.bubble") - Text("Subtitles") + L10n.subtitles.text } .padding() } @@ -106,7 +106,7 @@ struct SmallMediaStreamSelectionView: View { if updateFocusedLayer == .audio { HStack(spacing: 15) { Image(systemName: "speaker.wave.3") - Text("Audio") + L10n.audio.text } .padding() .background(Color.white) @@ -114,7 +114,7 @@ struct SmallMediaStreamSelectionView: View { } else { HStack(spacing: 15) { Image(systemName: "speaker.wave.3") - Text("Audio") + L10n.audio.text } .padding() } @@ -138,7 +138,7 @@ struct SmallMediaStreamSelectionView: View { if updateFocusedLayer == .playbackSpeed { HStack(spacing: 15) { Image(systemName: "speedometer") - Text("Playback Speed") + L10n.playbackSpeed.text } .padding() .background(Color.white) @@ -146,7 +146,7 @@ struct SmallMediaStreamSelectionView: View { } else { HStack(spacing: 15) { Image(systemName: "speedometer") - Text("Playback Speed") + L10n.playbackSpeed.text } .padding() } @@ -185,7 +185,7 @@ struct SmallMediaStreamSelectionView: View { HStack { if viewModel.subtitleStreams.isEmpty { Button {} label: { - Text("None") + L10n.none.text } } else { ForEach(viewModel.subtitleStreams, id: \.self) { subtitleStream in @@ -193,9 +193,9 @@ struct SmallMediaStreamSelectionView: View { viewModel.selectedSubtitleStreamIndex = subtitleStream.index ?? -1 } label: { if subtitleStream.index == viewModel.selectedSubtitleStreamIndex { - Label(subtitleStream.displayTitle ?? "No Title", systemImage: "checkmark") + Label(subtitleStream.displayTitle ?? L10n.noTitle, systemImage: "checkmark") } else { - Text(subtitleStream.displayTitle ?? "No Title") + Text(subtitleStream.displayTitle ?? L10n.noTitle) } } } @@ -220,9 +220,9 @@ struct SmallMediaStreamSelectionView: View { viewModel.selectedAudioStreamIndex = audioStream.index ?? -1 } label: { if audioStream.index == viewModel.selectedAudioStreamIndex { - Label(audioStream.displayTitle ?? "No Title", systemImage: "checkmark") + Label(audioStream.displayTitle ?? L10n.noTitle, systemImage: "checkmark") } else { - Text(audioStream.displayTitle ?? "No Title") + Text(audioStream.displayTitle ?? L10n.noTitle) } } } diff --git a/Swiftfin.xcodeproj/project.pbxproj b/Swiftfin.xcodeproj/project.pbxproj index efcba84f..c0e57467 100644 --- a/Swiftfin.xcodeproj/project.pbxproj +++ b/Swiftfin.xcodeproj/project.pbxproj @@ -375,8 +375,6 @@ E1AA33222782648000F6439C /* OverlaySliderColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1AA33212782648000F6439C /* OverlaySliderColor.swift */; }; E1AA33232782648000F6439C /* OverlaySliderColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1AA33212782648000F6439C /* OverlaySliderColor.swift */; }; E1AA332427829B5200F6439C /* OverlayType.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1AA331E2782639D00F6439C /* OverlayType.swift */; }; - E1AD104A26D94822003E4A08 /* DetailItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1AD104926D94822003E4A08 /* DetailItem.swift */; }; - E1AD104B26D94822003E4A08 /* DetailItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1AD104926D94822003E4A08 /* DetailItem.swift */; }; E1AD104D26D96CE3003E4A08 /* BaseItemDtoExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1AD104C26D96CE3003E4A08 /* BaseItemDtoExtensions.swift */; }; E1AD104E26D96CE3003E4A08 /* BaseItemDtoExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1AD104C26D96CE3003E4A08 /* BaseItemDtoExtensions.swift */; }; E1AD105426D97161003E4A08 /* BaseItemDtoExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1AD104C26D96CE3003E4A08 /* BaseItemDtoExtensions.swift */; }; @@ -721,7 +719,6 @@ E1AA331C2782541500F6439C /* PrimaryButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrimaryButtonView.swift; sourceTree = ""; }; E1AA331E2782639D00F6439C /* OverlayType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OverlayType.swift; sourceTree = ""; }; E1AA33212782648000F6439C /* OverlaySliderColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OverlaySliderColor.swift; sourceTree = ""; }; - E1AD104926D94822003E4A08 /* DetailItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailItem.swift; sourceTree = ""; }; E1AD104C26D96CE3003E4A08 /* BaseItemDtoExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseItemDtoExtensions.swift; sourceTree = ""; }; E1AD105526D981CE003E4A08 /* PortraitHStackView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PortraitHStackView.swift; sourceTree = ""; }; E1AD105B26D9ABDD003E4A08 /* PillHStackView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PillHStackView.swift; sourceTree = ""; }; @@ -974,7 +971,6 @@ children = ( E1D4BF802719D22800A11E64 /* AppAppearance.swift */, E1D4BF862719D27100A11E64 /* Bitrates.swift */, - E1AD104926D94822003E4A08 /* DetailItem.swift */, 53192D5C265AA78A008A4215 /* DeviceProfileBuilder.swift */, 62EC353326766B03000E9F2D /* DeviceRotationViewModifier.swift */, E19169CD272514760085832A /* HTTPScheme.swift */, @@ -1674,7 +1670,6 @@ buildPhases = ( 3D0F2756C71CDF6B9EEBD4E0 /* [CP] Check Pods Manifest.lock */, 6286F0A3271C0ABA00C40ED5 /* R.swift */, - C6EE6AB295A273FF14E6EF56 /* [CP] Prepare Artifacts */, 5358705C2669D21600D05A09 /* Sources */, 5358705D2669D21600D05A09 /* Frameworks */, 5358705E2669D21600D05A09 /* Resources */, @@ -1819,7 +1814,7 @@ 536D3D82267BEA550004248C /* XCRemoteSwiftPackageReference "ParallaxView" */, 53649AAB269CFAEA00A2D8B7 /* XCRemoteSwiftPackageReference "Puppy" */, 62C29E9A26D0FE4100C1D2E7 /* XCRemoteSwiftPackageReference "stinsen" */, - E13DD3C42716499E009D4DAF /* XCRemoteSwiftPackageReference "CoreStore" */, + E13DD3C42716499E009D4DAF /* XCRemoteSwiftPackageReference "CoreStore.git" */, E13DD3D127168E65009D4DAF /* XCRemoteSwiftPackageReference "Defaults" */, E1267D42271A212C003C492E /* XCRemoteSwiftPackageReference "CombineExt" */, E1C16B89271A2180009A5D25 /* XCRemoteSwiftPackageReference "SwiftyJSON" */, @@ -2033,23 +2028,6 @@ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Swiftfin iOS/Pods-Swiftfin iOS-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; - C6EE6AB295A273FF14E6EF56 /* [CP] Prepare Artifacts */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Swiftfin tvOS/Pods-Swiftfin tvOS-artifacts-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Prepare Artifacts"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Swiftfin tvOS/Pods-Swiftfin tvOS-artifacts-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Swiftfin tvOS/Pods-Swiftfin tvOS-artifacts.sh\"\n"; - showEnvVarsInLog = 0; - }; D4D3981ADF75BCD341D590C0 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -2148,7 +2126,6 @@ 62EC3530267666A5000E9F2D /* SessionManager.swift in Sources */, E1E5D5372783A52C00692DFE /* CinematicEpisodeItemView.swift in Sources */, C4BE078E27298818003F4AD1 /* LiveTVHomeView.swift in Sources */, - E1AD104B26D94822003E4A08 /* DetailItem.swift in Sources */, E13DD3E227176BD3009D4DAF /* ServerListViewModel.swift in Sources */, 53272539268C20100035FBF1 /* EpisodeItemView.swift in Sources */, E178859B2780F1F40094FBCF /* tvOSSlider.swift in Sources */, @@ -2375,7 +2352,6 @@ E13DD3E927177ED6009D4DAF /* ServerListCoordinator.swift in Sources */, E1C812BD277A8E5D00918266 /* PlayerOverlayDelegate.swift in Sources */, E13DD3C227164941009D4DAF /* SwiftfinStore.swift in Sources */, - E1AD104A26D94822003E4A08 /* DetailItem.swift in Sources */, 62E632E0267D30CA0063E547 /* LibraryViewModel.swift in Sources */, E193D4DB27193CCA00900D82 /* PillStackable.swift in Sources */, E1AA331F2782639D00F6439C /* OverlayType.swift in Sources */, @@ -2797,7 +2773,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 66; DEVELOPMENT_ASSET_PATHS = ""; - DEVELOPMENT_TEAM = ""; + DEVELOPMENT_TEAM = TY84JMYEFE; ENABLE_BITCODE = NO; ENABLE_PREVIEWS = YES; EXCLUDED_ARCHS = ""; @@ -2834,7 +2810,7 @@ CURRENT_PROJECT_VERSION = 66; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = ""; - DEVELOPMENT_TEAM = ""; + DEVELOPMENT_TEAM = TY84JMYEFE; ENABLE_BITCODE = NO; ENABLE_PREVIEWS = YES; EXCLUDED_ARCHS = ""; @@ -2865,7 +2841,7 @@ ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 66; - DEVELOPMENT_TEAM = ""; + DEVELOPMENT_TEAM = TY84JMYEFE; INFOPLIST_FILE = WidgetExtension/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( @@ -2892,7 +2868,7 @@ ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 66; - DEVELOPMENT_TEAM = ""; + DEVELOPMENT_TEAM = TY84JMYEFE; INFOPLIST_FILE = WidgetExtension/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( @@ -3024,7 +3000,7 @@ minimumVersion = 1.0.0; }; }; - E13DD3C42716499E009D4DAF /* XCRemoteSwiftPackageReference "CoreStore" */ = { + E13DD3C42716499E009D4DAF /* XCRemoteSwiftPackageReference "CoreStore.git" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/JohnEstropia/CoreStore.git"; requirement = { @@ -3141,17 +3117,17 @@ }; E13DD3C52716499E009D4DAF /* CoreStore */ = { isa = XCSwiftPackageProductDependency; - package = E13DD3C42716499E009D4DAF /* XCRemoteSwiftPackageReference "CoreStore" */; + package = E13DD3C42716499E009D4DAF /* XCRemoteSwiftPackageReference "CoreStore.git" */; productName = CoreStore; }; E13DD3CC27164CA7009D4DAF /* CoreStore */ = { isa = XCSwiftPackageProductDependency; - package = E13DD3C42716499E009D4DAF /* XCRemoteSwiftPackageReference "CoreStore" */; + package = E13DD3C42716499E009D4DAF /* XCRemoteSwiftPackageReference "CoreStore.git" */; productName = CoreStore; }; E13DD3CE27164E1F009D4DAF /* CoreStore */ = { isa = XCSwiftPackageProductDependency; - package = E13DD3C42716499E009D4DAF /* XCRemoteSwiftPackageReference "CoreStore" */; + package = E13DD3C42716499E009D4DAF /* XCRemoteSwiftPackageReference "CoreStore.git" */; productName = CoreStore; }; E13DD3D227168E65009D4DAF /* Defaults */ = { diff --git a/Swiftfin/Components/EpisodesRowView.swift b/Swiftfin/Components/EpisodesRowView.swift index fa8e962a..4acc1872 100644 --- a/Swiftfin/Components/EpisodesRowView.swift +++ b/Swiftfin/Components/EpisodesRowView.swift @@ -26,15 +26,15 @@ struct EpisodesRowView: View { viewModel.selectedSeason = season } label: { if season.id == viewModel.selectedSeason?.id { - Label(season.name ?? "Season", systemImage: "checkmark") + Label(season.name ?? L10n.season, systemImage: "checkmark") } else { - Text(season.name ?? "Season") + Text(season.name ?? L10n.season) } } } } label: { HStack(spacing: 5) { - Text(viewModel.selectedSeason?.name ?? "Unknown") + Text(viewModel.selectedSeason?.name ?? L10n.unknown) .fontWeight(.semibold) .fixedSize() Image(systemName: "chevron.down") @@ -85,7 +85,8 @@ struct EpisodesRowView: View { Text("--") .font(.footnote) .foregroundColor(.secondary) - Text("No episodes available") + + L10n.noEpisodesAvailable.text .font(.body) .padding(.bottom, 1) .lineLimit(2) diff --git a/Swiftfin/Components/TruncatedTextView.swift b/Swiftfin/Components/TruncatedTextView.swift index 71e389b5..9e787719 100644 --- a/Swiftfin/Components/TruncatedTextView.swift +++ b/Swiftfin/Components/TruncatedTextView.swift @@ -23,7 +23,7 @@ struct TruncatedTextView: View { if !truncated { return "" } else { - return "See More" + return L10n.seeMore } } diff --git a/Swiftfin/Views/BasicAppSettingsView.swift b/Swiftfin/Views/BasicAppSettingsView.swift index 7da5a76b..b1993ded 100644 --- a/Swiftfin/Views/BasicAppSettingsView.swift +++ b/Swiftfin/Views/BasicAppSettingsView.swift @@ -41,55 +41,55 @@ struct BasicAppSettingsView: View { } Section { - Picker("Default Scheme", selection: $defaultHTTPScheme) { + Picker(L10n.defaultScheme, selection: $defaultHTTPScheme) { ForEach(HTTPScheme.allCases, id: \.self) { scheme in Text("\(scheme.rawValue)") } } } header: { - Text("Networking") + L10n.networking.text } Button { resetUserSettingsTapped = true } label: { - Text("Reset User Settings") + L10n.resetUserSettings.text } Button { resetAppSettingsTapped = true } label: { - Text("Reset App Settings") + L10n.resetAppSettings.text } Button { removeAllUsersTapped = true } label: { - Text("Remove All Users") + L10n.removeAllUsers.text } } - .alert("Reset User Settings", isPresented: $resetUserSettingsTapped, actions: { + .alert(L10n.resetUserSettings, isPresented: $resetUserSettingsTapped, actions: { Button(role: .destructive) { viewModel.resetUserSettings() } label: { L10n.reset.text } }) - .alert("Reset App Settings", isPresented: $resetAppSettingsTapped, actions: { + .alert(L10n.resetAppSettings, isPresented: $resetAppSettingsTapped, actions: { Button(role: .destructive) { viewModel.resetAppSettings() } label: { L10n.reset.text } }) - .alert("Remove All Users", isPresented: $removeAllUsersTapped, actions: { + .alert(L10n.removeAllUsers, isPresented: $removeAllUsersTapped, actions: { Button(role: .destructive) { viewModel.removeAllUsers() } label: { L10n.reset.text } }) - .navigationBarTitle("Settings", displayMode: .inline) + .navigationBarTitle(L10n.settings, displayMode: .inline) .toolbar { ToolbarItemGroup(placement: .navigationBarLeading) { Button { diff --git a/Swiftfin/Views/ConnectToServerView.swift b/Swiftfin/Views/ConnectToServerView.swift index 6b12462c..2cae951a 100644 --- a/Swiftfin/Views/ConnectToServerView.swift +++ b/Swiftfin/Views/ConnectToServerView.swift @@ -37,7 +37,7 @@ struct ConnectToServerView: View { Button(role: .destructive) { viewModel.cancelConnection() } label: { - Text("Cancel") + L10n.cancel.text } } else { Button { @@ -48,17 +48,14 @@ struct ConnectToServerView: View { .disabled(uri.isEmpty) } } header: { - Text("Connect to a Jellyfin server") + L10n.connectToJellyfinServer.text } Section { if viewModel.searching { HStack(alignment: .center, spacing: 5) { Spacer() - // Oct. 15, 2021 - // There is a bug where ProgressView() won't appear sometimes when searching, - // dots were used instead but ProgressView() is preferred - Text("Searching...") + L10n.searchingDots.text .foregroundColor(.secondary) Spacer() } @@ -66,7 +63,7 @@ struct ConnectToServerView: View { if viewModel.discoveredServers.isEmpty { HStack(alignment: .center) { Spacer() - Text("No local servers found") + L10n.noLocalServersFound.text .font(.callout) .foregroundColor(.secondary) Spacer() @@ -106,7 +103,7 @@ struct ConnectToServerView: View { } .alert(item: $viewModel.errorMessage) { _ in Alert(title: Text(viewModel.alertTitle), - message: Text(viewModel.errorMessage?.displayMessage ?? "Unknown Error"), + message: Text(viewModel.errorMessage?.displayMessage ?? L10n.unknownError), dismissButton: .cancel()) } .alert(item: $viewModel.addServerURIPayload) { _ in diff --git a/Swiftfin/Views/ContinueWatchingView.swift b/Swiftfin/Views/ContinueWatchingView.swift index 9f4d3f3e..172e71a6 100644 --- a/Swiftfin/Views/ContinueWatchingView.swift +++ b/Swiftfin/Views/ContinueWatchingView.swift @@ -43,7 +43,7 @@ struct ContinueWatchingView: View { .frame(height: 35) VStack(alignment: .leading, spacing: 0) { - Text(item.getItemProgressString() ?? "Continue") + Text(item.getItemProgressString() ?? L10n.continue) .font(.subheadline) .padding(.bottom, 5) .padding(.leading, 10) diff --git a/Swiftfin/Views/HomeView.swift b/Swiftfin/Views/HomeView.swift index 4e6ddacb..751ccb4d 100644 --- a/Swiftfin/Views/HomeView.swift +++ b/Swiftfin/Views/HomeView.swift @@ -39,7 +39,7 @@ struct HomeView: View { .frame(minWidth: 50, maxWidth: 240) .multilineTextAlignment(.center) - PrimaryButtonView(title: "Retry") { + PrimaryButtonView(title: L10n.retry) { viewModel.refresh() } } @@ -69,7 +69,7 @@ struct HomeView: View { if !viewModel.latestAddedItems.isEmpty { PortraitImageHStackView(items: viewModel.latestAddedItems) { - Text("Recently Added") + L10n.recentlyAdded.text .font(.title2) .fontWeight(.bold) .padding() diff --git a/Swiftfin/Views/ItemOverviewView.swift b/Swiftfin/Views/ItemOverviewView.swift index b9850270..b9101b3d 100644 --- a/Swiftfin/Views/ItemOverviewView.swift +++ b/Swiftfin/Views/ItemOverviewView.swift @@ -21,7 +21,7 @@ struct ItemOverviewView: View { .font(.footnote) .padding() } - .navigationBarTitle("Overview", displayMode: .inline) + .navigationBarTitle(L10n.overview, displayMode: .inline) .toolbar { ToolbarItemGroup(placement: .navigationBarLeading) { Button { diff --git a/Swiftfin/Views/ItemView/ItemViewBody.swift b/Swiftfin/Views/ItemView/ItemViewBody.swift index 7d8dadc5..e89c27d7 100644 --- a/Swiftfin/Views/ItemView/ItemViewBody.swift +++ b/Swiftfin/Views/ItemView/ItemViewBody.swift @@ -42,7 +42,7 @@ struct ItemViewBody: View { .padding() } } else { - Text("No overview available") + L10n.noOverviewAvailable.text .font(.footnote) .padding() } @@ -92,7 +92,7 @@ struct ItemViewBody: View { if let seriesItem = episodeViewModel.series { let a = [seriesItem] PortraitImageHStackView(items: a) { - Text("Series") + L10n.series.text .fontWeight(.semibold) .padding(.bottom) .padding(.horizontal) @@ -106,7 +106,7 @@ struct ItemViewBody: View { if let collectionViewModel = viewModel as? CollectionItemViewModel { PortraitImageHStackView(items: collectionViewModel.collectionItems) { - Text("Items") + L10n.items.text .fontWeight(.semibold) .padding(.bottom) .padding(.horizontal) @@ -121,7 +121,7 @@ struct ItemViewBody: View { if let castAndCrew = viewModel.item.people { PortraitImageHStackView(items: castAndCrew.filter { BaseItemPerson.DisplayedType.allCasesRaw.contains($0.type ?? "") }, topBarView: { - Text("Cast & Crew") + L10n.castAndCrew.text .fontWeight(.semibold) .padding(.bottom) .padding(.horizontal) diff --git a/Swiftfin/Views/ItemView/ItemViewDetailsView.swift b/Swiftfin/Views/ItemView/ItemViewDetailsView.swift index ed221407..846e9960 100644 --- a/Swiftfin/Views/ItemView/ItemViewDetailsView.swift +++ b/Swiftfin/Views/ItemView/ItemViewDetailsView.swift @@ -19,7 +19,7 @@ struct ItemViewDetailsView: View { if !viewModel.informationItems.isEmpty { VStack(alignment: .leading, spacing: 20) { - Text("Information") + L10n.information.text .font(.title3) .fontWeight(.bold) @@ -38,7 +38,7 @@ struct ItemViewDetailsView: View { if !viewModel.mediaItems.isEmpty { VStack(alignment: .leading, spacing: 20) { - Text("Media") + L10n.media.text .font(.title3) .fontWeight(.bold) diff --git a/Swiftfin/Views/LibraryListView.swift b/Swiftfin/Views/LibraryListView.swift index 3cea0fcb..0147bf2a 100644 --- a/Swiftfin/Views/LibraryListView.swift +++ b/Swiftfin/Views/LibraryListView.swift @@ -21,7 +21,7 @@ struct LibraryListView: View { LazyVStack { Button { libraryListRouter.route(to: \.library, - (viewModel: LibraryViewModel(filters: viewModel.withFavorites), title: "Favorites")) + (viewModel: LibraryViewModel(filters: viewModel.withFavorites), title: L10n.favorites)) } label: { ZStack { HStack { diff --git a/Swiftfin/Views/LibrarySearchView.swift b/Swiftfin/Views/LibrarySearchView.swift index 4d942af7..ae26e6ee 100644 --- a/Swiftfin/Views/LibrarySearchView.swift +++ b/Swiftfin/Views/LibrarySearchView.swift @@ -45,7 +45,7 @@ struct LibrarySearchView: View { .onChange(of: searchQuery) { query in viewModel.searchQuerySubject.send(query) } - .navigationBarTitle("Search", displayMode: .inline) + .navigationBarTitle(L10n.search, displayMode: .inline) } var suggestionsListView: some View { diff --git a/Swiftfin/Views/ServerDetailView.swift b/Swiftfin/Views/ServerDetailView.swift index 5bd8645a..7df0a03f 100644 --- a/Swiftfin/Views/ServerDetailView.swift +++ b/Swiftfin/Views/ServerDetailView.swift @@ -22,15 +22,15 @@ struct ServerDetailView: View { var body: some View { Form { - Section(header: Text("Server Details")) { + Section(header: L10n.serverDetails.text) { HStack { - Text("Name") + L10n.name.text Spacer() Text(viewModel.server.name) .foregroundColor(.secondary) } - Picker("URI", selection: $currentServerURI) { + Picker(L10n.url, selection: $currentServerURI) { ForEach(viewModel.server.uris.sorted(), id: \.self) { uri in Text(uri).tag(uri) .foregroundColor(.secondary) @@ -40,14 +40,14 @@ struct ServerDetailView: View { } HStack { - Text("Version") + L10n.version.text Spacer() Text(viewModel.server.version) .foregroundColor(.secondary) } HStack { - Text("Operating System") + L10n.operatingSystem.text Spacer() Text(viewModel.server.os) .foregroundColor(.secondary) diff --git a/Swiftfin/Views/ServerListView.swift b/Swiftfin/Views/ServerListView.swift index 9502189a..26336a0b 100644 --- a/Swiftfin/Views/ServerListView.swift +++ b/Swiftfin/Views/ServerListView.swift @@ -56,7 +56,7 @@ struct ServerListView: View { Button(role: .destructive) { viewModel.remove(server: server) } label: { - Label("Remove", systemImage: "trash") + Label(L10n.remove, systemImage: "trash") } } } @@ -66,7 +66,7 @@ struct ServerListView: View { private var noServerView: some View { VStack { - Text("Connect to a Jellyfin server to get started") + L10n.connectToJellyfinServerStart.text .frame(minWidth: 50, maxWidth: 240) .multilineTextAlignment(.center) @@ -109,7 +109,7 @@ struct ServerListView: View { var body: some View { innerBody - .navigationTitle("Servers") + .navigationTitle(L10n.servers) .toolbar { ToolbarItemGroup(placement: .navigationBarTrailing) { trailingToolbarContent diff --git a/Swiftfin/Views/SettingsView/ExperimentalSettingsView.swift b/Swiftfin/Views/SettingsView/ExperimentalSettingsView.swift index 49fbb6fc..e2334b23 100644 --- a/Swiftfin/Views/SettingsView/ExperimentalSettingsView.swift +++ b/Swiftfin/Views/SettingsView/ExperimentalSettingsView.swift @@ -21,7 +21,7 @@ struct ExperimentalSettingsView: View { Toggle("Sync Subtitles with Adjacent Episodes", isOn: $syncSubtitleStateWithAdjacent) } header: { - Text("Experimental") + L10n.experimental.text } } } diff --git a/Swiftfin/Views/SettingsView/OverlaySettingsView.swift b/Swiftfin/Views/SettingsView/OverlaySettingsView.swift index e7d58ee8..795d37a2 100644 --- a/Swiftfin/Views/SettingsView/OverlaySettingsView.swift +++ b/Swiftfin/Views/SettingsView/OverlaySettingsView.swift @@ -24,17 +24,35 @@ struct OverlaySettingsView: View { var body: some View { Form { - Section(header: Text("Overlay")) { - Picker("Overlay Type", selection: $overlayType) { + Section(header: L10n.overlay.text) { + Picker(L10n.overlayType, selection: $overlayType) { ForEach(OverlayType.allCases, id: \.self) { overlay in Text(overlay.label).tag(overlay) } } - Toggle("\(Image(systemName: "chevron.left.circle")) Play Previous Item", isOn: $shouldShowPlayPreviousItem) - Toggle("\(Image(systemName: "chevron.right.circle")) Play Next Item", isOn: $shouldShowPlayNextItem) - Toggle("\(Image(systemName: "play.circle.fill")) Auto Play", isOn: $shouldShowAutoPlay) - Toggle("Edit Jump Lengths", isOn: $shouldShowJumpButtonsInOverlayMenu) + Toggle(isOn: $shouldShowPlayPreviousItem) { + HStack { + Image(systemName: "chevron.left.circle") + L10n.playPreviousItem.text + } + } + + Toggle(isOn: $shouldShowPlayNextItem) { + HStack { + Image(systemName: "chevron.right.circle") + L10n.playNextItem.text + } + } + + Toggle(isOn: $shouldShowAutoPlay) { + HStack { + Image(systemName: "play.circle.fill") + L10n.autoPlay.text + } + } + + Toggle(L10n.editJumpLengths, isOn: $shouldShowJumpButtonsInOverlayMenu) } } } diff --git a/Swiftfin/Views/SettingsView/SettingsView.swift b/Swiftfin/Views/SettingsView/SettingsView.swift index 7cb0e00a..30613b87 100644 --- a/Swiftfin/Views/SettingsView/SettingsView.swift +++ b/Swiftfin/Views/SettingsView/SettingsView.swift @@ -51,7 +51,7 @@ struct SettingsView: View { Form { Section(header: EmptyView()) { HStack { - Text("User") + L10n.user.text Spacer() Text(viewModel.user.username) .foregroundColor(.jellyfinPurple) @@ -61,7 +61,7 @@ struct SettingsView: View { settingsRouter.route(to: \.serverDetail) } label: { HStack { - Text("Server") + L10n.server.text .foregroundColor(.primary) Spacer() Text(viewModel.server.name) @@ -76,7 +76,7 @@ struct SettingsView: View { SessionManager.main.logout() } } label: { - Text("Switch User") + L10n.switchUser.text .font(.callout) } } @@ -96,28 +96,28 @@ struct SettingsView: View { // } // } - Section(header: Text("Video Player")) { - Picker("Jump Forward Length", selection: $jumpForwardLength) { + Section(header: L10n.videoPlayer.text) { + Picker(L10n.jumpForwardLength, selection: $jumpForwardLength) { ForEach(VideoPlayerJumpLength.allCases, id: \.self) { length in Text(length.label).tag(length.rawValue) } } - Picker("Jump Backward Length", selection: $jumpBackwardLength) { + Picker(L10n.jumpBackwardLength, selection: $jumpBackwardLength) { ForEach(VideoPlayerJumpLength.allCases, id: \.self) { length in Text(length.label).tag(length.rawValue) } } - Toggle("Jump Gestures Enabled", isOn: $jumpGesturesEnabled) + Toggle(L10n.jumpGesturesEnabled, isOn: $jumpGesturesEnabled) - Toggle("Resume 5 Second Offset", isOn: $resumeOffset) + Toggle(L10n.resume5SecondOffset, isOn: $resumeOffset) Button { settingsRouter.route(to: \.overlaySettings) } label: { HStack { - Text("Overlay") + L10n.overlay.text .foregroundColor(.primary) Spacer() Text(overlayType.label) @@ -129,7 +129,7 @@ struct SettingsView: View { settingsRouter.route(to: \.experimentalSettings) } label: { HStack { - Text("Experimental") + L10n.experimental.text .foregroundColor(.primary) Spacer() Image(systemName: "chevron.right") @@ -138,22 +138,22 @@ struct SettingsView: View { } Section(header: L10n.accessibility.text) { - Toggle("Show Poster Labels", isOn: $showPosterLabels) - Toggle("Show Cast and Crew", isOn: $showCastAndCrew) + Toggle(L10n.showPosterLabels, isOn: $showPosterLabels) + Toggle(L10n.showCastAndCrew, isOn: $showCastAndCrew) Picker(L10n.appearance, selection: $appAppearance) { ForEach(AppAppearance.allCases, id: \.self) { appearance in Text(appearance.localizedName).tag(appearance.rawValue) } } - Picker("Subtitle size", selection: $subtitleSize) { + Picker(L10n.subtitleSize, selection: $subtitleSize) { ForEach(SubtitleSize.allCases, id: \.self) { size in Text(size.label).tag(size.rawValue) } } } } - .navigationBarTitle("Settings", displayMode: .inline) + .navigationBarTitle(L10n.settings, displayMode: .inline) .toolbar { ToolbarItemGroup(placement: .navigationBarLeading) { Button { diff --git a/Swiftfin/Views/UserListView.swift b/Swiftfin/Views/UserListView.swift index dd43a15f..b36b03b2 100644 --- a/Swiftfin/Views/UserListView.swift +++ b/Swiftfin/Views/UserListView.swift @@ -45,7 +45,7 @@ struct UserListView: View { Button(role: .destructive) { viewModel.remove(user: user) } label: { - Label("Remove", systemImage: "trash") + Label(L10n.remove, systemImage: "trash") } } } @@ -55,7 +55,7 @@ struct UserListView: View { private var noUserView: some View { VStack { - Text("Sign in to get started") + L10n.signInGetStarted.text .frame(minWidth: 50, maxWidth: 240) .multilineTextAlignment(.center) @@ -71,7 +71,7 @@ struct UserListView: View { .padding(.horizontal, 30) .padding([.top, .bottom], 20) - Text("Sign in") + L10n.signIn.text .foregroundColor(Color.white) .bold() } diff --git a/Swiftfin/Views/UserSignInView.swift b/Swiftfin/Views/UserSignInView.swift index cbc460e1..5e6888b1 100644 --- a/Swiftfin/Views/UserSignInView.swift +++ b/Swiftfin/Views/UserSignInView.swift @@ -34,26 +34,26 @@ struct UserSignInView: View { Button(role: .destructive) { viewModel.cancelSignIn() } label: { - Text("Cancel") + L10n.cancel.text } } else { Button { viewModel.login(username: username, password: password) } label: { - Text("Sign In") + L10n.signIn.text } .disabled(username.isEmpty) } } header: { - Text("Sign In to \(viewModel.server.name)") + L10n.signInToServer(viewModel.server.name).text } } .alert(item: $viewModel.errorMessage) { _ in Alert(title: Text(viewModel.alertTitle), - message: Text(viewModel.errorMessage?.displayMessage ?? "Unknown Error"), + message: Text(viewModel.errorMessage?.displayMessage ?? L10n.unknownError), dismissButton: .cancel()) } - .navigationTitle("Sign In") + .navigationTitle(L10n.signIn) .navigationBarBackButtonHidden(viewModel.isLoading) } } diff --git a/Swiftfin/Views/VideoPlayer/VLCPlayerOverlayView.swift b/Swiftfin/Views/VideoPlayer/VLCPlayerOverlayView.swift index 6b19fe5d..9afaa91c 100644 --- a/Swiftfin/Views/VideoPlayer/VLCPlayerOverlayView.swift +++ b/Swiftfin/Views/VideoPlayer/VLCPlayerOverlayView.swift @@ -142,16 +142,16 @@ struct VLCPlayerOverlayView: View { viewModel.selectedAudioStreamIndex = audioStream.index ?? -1 } label: { if audioStream.index == viewModel.selectedAudioStreamIndex { - Label(audioStream.displayTitle ?? "No Title", systemImage: "checkmark") + Label(audioStream.displayTitle ?? L10n.noTitle, systemImage: "checkmark") } else { - Text(audioStream.displayTitle ?? "No Title") + Text(audioStream.displayTitle ?? L10n.noTitle) } } } } label: { HStack { Image(systemName: "speaker.wave.3") - Text("Audio") + L10n.audio.text } } @@ -161,16 +161,16 @@ struct VLCPlayerOverlayView: View { viewModel.selectedSubtitleStreamIndex = subtitleStream.index ?? -1 } label: { if subtitleStream.index == viewModel.selectedSubtitleStreamIndex { - Label(subtitleStream.displayTitle ?? "No Title", systemImage: "checkmark") + Label(subtitleStream.displayTitle ?? L10n.noTitle, systemImage: "checkmark") } else { - Text(subtitleStream.displayTitle ?? "No Title") + Text(subtitleStream.displayTitle ?? L10n.noTitle) } } } } label: { HStack { Image(systemName: "captions.bubble") - Text("Subtitles") + L10n.subtitles.text } } @@ -189,7 +189,7 @@ struct VLCPlayerOverlayView: View { } label: { HStack { Image(systemName: "speedometer") - Text("Playback Speed") + L10n.playbackSpeed.text } } @@ -209,7 +209,7 @@ struct VLCPlayerOverlayView: View { } label: { HStack { Image(systemName: "goforward") - Text("Jump Forward Length") + L10n.jumpForwardLength.text } } @@ -228,7 +228,7 @@ struct VLCPlayerOverlayView: View { } label: { HStack { Image(systemName: "gobackward") - Text("Jump Backward Length") + L10n.jumpBackwardLength.text } } } @@ -337,10 +337,7 @@ struct VLCPlayerOverlayView: View { Capsule().foregroundColor(.purple)) .background(Capsule().foregroundColor(Color.gray.opacity(0.25))) .frame(height: 4), - thumb: Circle().foregroundColor(.purple) - .onLongPressGesture(perform: { - print("got it here") - }), + thumb: Circle().foregroundColor(.purple), thumbSize: CGSize.Circle(radius: viewModel.sliderIsScrubbing ? 20 : 15), thumbInteractiveSize: CGSize.Circle(radius: 40), options: .defaultOptions)) diff --git a/Translations/en.lproj/Localizable.strings b/Translations/en.lproj/Localizable.strings index a22e6cfc..c13da6ec 100644 Binary files a/Translations/en.lproj/Localizable.strings and b/Translations/en.lproj/Localizable.strings differ