Implement localization for hardcoded strings (#1510)

* first string

* add a bunch of localization

* more hardcode to localization

* small changes for two strings

* fix space formatting

* Update Localizable.strings

Put the localizations back in. Don't know why this changes anything but 🤷‍♂️

* Fix encoding

Why???

Also, missing ;

* implement requested changes

---------

Co-authored-by: Joe Kribs <jpkribs@outlook.com>
This commit is contained in:
Rasko 2025-05-02 19:04:34 +02:00 committed by GitHub
parent 78e9d86a34
commit 103982f6e7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
27 changed files with 124 additions and 58 deletions

View File

@ -31,7 +31,7 @@ struct TruncatedText: View {
private var isTruncatedBinding: Binding<Bool> private var isTruncatedBinding: Binding<Bool>
private var onSeeMore: () -> Void private var onSeeMore: () -> Void
private let seeMoreText = "\u{2026} See More" private let seeMoreText = "\u{2026}" + L10n.seeMore
private var seeMoreType: SeeMoreType private var seeMoreType: SeeMoreType
private let text: String private let text: String

View File

@ -17,9 +17,9 @@ extension ItemSortOrder: Displayable {
var displayTitle: String { var displayTitle: String {
switch self { switch self {
case .ascending: case .ascending:
return "Ascending" return L10n.ascending
case .descending: case .descending:
return "Descending" return L10n.descending
} }
} }
} }

View File

@ -19,7 +19,7 @@ enum CustomDeviceProfileAction: String, CaseIterable, Displayable, Storable {
case .add: case .add:
return L10n.add return L10n.add
case .replace: case .replace:
return "Replace" return L10n.replace
} }
} }
} }

View File

@ -26,7 +26,7 @@ enum LongPressAction: String, GestureAction {
case .none: case .none:
return L10n.none return L10n.none
case .gestureLock: case .gestureLock:
return "Gesture Lock" return L10n.gestureLock
} }
} }
} }
@ -60,7 +60,7 @@ enum DoubleTouchAction: String, GestureAction {
case .aspectFill: case .aspectFill:
return L10n.aspectFill return L10n.aspectFill
case .gestureLock: case .gestureLock:
return "Gesture Lock" return L10n.gestureLock
case .pausePlay: case .pausePlay:
return L10n.playAndPause return L10n.playAndPause
} }
@ -85,17 +85,17 @@ enum PanAction: String, GestureAction {
case .audioffset: case .audioffset:
return L10n.audioOffset return L10n.audioOffset
case .brightness: case .brightness:
return "Brightness" return L10n.brightness
case .playbackSpeed: case .playbackSpeed:
return L10n.playbackSpeed return L10n.playbackSpeed
case .scrub: case .scrub:
return "Scrub" return L10n.scrub
case .slowScrub: case .slowScrub:
return "Slow Scrub" return L10n.slowScrub
case .subtitleOffset: case .subtitleOffset:
return L10n.subtitleOffset return L10n.subtitleOffset
case .volume: case .volume:
return "Volume" return L10n.volume
} }
} }
} }

View File

@ -32,7 +32,7 @@ enum PlaybackButtonType: String, CaseIterable, Displayable, Defaults.Serializabl
var displayTitle: String { var displayTitle: String {
switch self { switch self {
case .large: case .large:
return "Large" return L10n.large
case .compact: case .compact:
return L10n.compact return L10n.compact
} }

View File

@ -15,13 +15,12 @@ enum PosterDisplayType: String, CaseIterable, Displayable, Storable, SystemImage
case landscape case landscape
case portrait case portrait
// TODO: localize
var displayTitle: String { var displayTitle: String {
switch self { switch self {
case .landscape: case .landscape:
"Landscape" L10n.landscape
case .portrait: case .portrait:
"Portrait" L10n.portrait
} }
} }

View File

@ -17,9 +17,9 @@ enum SliderType: String, CaseIterable, Displayable, Defaults.Serializable {
var displayTitle: String { var displayTitle: String {
switch self { switch self {
case .thumb: case .thumb:
return "Thumb" return L10n.thumbSlider
case .capsule: case .capsule:
return "Capsule" return L10n.capsule
} }
} }
} }

View File

@ -17,7 +17,7 @@ enum TimestampType: String, CaseIterable, Defaults.Serializable, Displayable {
var displayTitle: String { var displayTitle: String {
switch self { switch self {
case .split: case .split:
return "Split" return L10n.split
case .compact: case .compact:
return L10n.compact return L10n.compact
} }

View File

@ -17,9 +17,9 @@ enum TrailingTimestampType: String, CaseIterable, Displayable, Defaults.Serializ
var displayTitle: String { var displayTitle: String {
switch self { switch self {
case .timeLeft: case .timeLeft:
return "Time left" return L10n.timeLeft
case .totalTime: case .totalTime:
return "Total time" return L10n.totalTime
} }
} }
} }

View File

@ -23,7 +23,7 @@ enum UserAccessPolicy: String, CaseIterable, Codable, Displayable {
case .none: case .none:
L10n.none L10n.none
case .requireDeviceAuthentication: case .requireDeviceAuthentication:
"Device Authentication" L10n.deviceAuth
case .requirePin: case .requirePin:
L10n.pin L10n.pin
} }

View File

@ -19,7 +19,7 @@ enum VideoPlayerType: String, CaseIterable, Defaults.Serializable, Displayable {
var displayTitle: String { var displayTitle: String {
switch self { switch self {
case .native: case .native:
"Native" L10n.native
case .swiftfin: case .swiftfin:
"Swiftfin" "Swiftfin"
} }

View File

@ -128,6 +128,8 @@ internal enum L10n {
internal static let art = L10n.tr("Localizable", "art", fallback: "Art") internal static let art = L10n.tr("Localizable", "art", fallback: "Art")
/// Artist /// Artist
internal static let artist = L10n.tr("Localizable", "artist", fallback: "Artist") internal static let artist = L10n.tr("Localizable", "artist", fallback: "Artist")
/// Ascending
internal static let ascending = L10n.tr("Localizable", "ascending", fallback: "Ascending")
/// Aspect Fill /// Aspect Fill
internal static let aspectFill = L10n.tr("Localizable", "aspectFill", fallback: "Aspect Fill") internal static let aspectFill = L10n.tr("Localizable", "aspectFill", fallback: "Aspect Fill")
/// Audio /// Audio
@ -238,6 +240,8 @@ internal enum L10n {
internal static let box = L10n.tr("Localizable", "box", fallback: "Box") internal static let box = L10n.tr("Localizable", "box", fallback: "Box")
/// BoxRear /// BoxRear
internal static let boxRear = L10n.tr("Localizable", "boxRear", fallback: "BoxRear") internal static let boxRear = L10n.tr("Localizable", "boxRear", fallback: "BoxRear")
/// Brightness
internal static let brightness = L10n.tr("Localizable", "brightness", fallback: "Brightness")
/// Bugs and Features /// Bugs and Features
internal static let bugsAndFeatures = L10n.tr("Localizable", "bugsAndFeatures", fallback: "Bugs and Features") internal static let bugsAndFeatures = L10n.tr("Localizable", "bugsAndFeatures", fallback: "Bugs and Features")
/// Buttons /// Buttons
@ -250,12 +254,16 @@ internal enum L10n {
internal static let cannotConnectToHost = L10n.tr("Localizable", "cannotConnectToHost", fallback: "Cannot connect to host") internal static let cannotConnectToHost = L10n.tr("Localizable", "cannotConnectToHost", fallback: "Cannot connect to host")
/// Capabilities /// Capabilities
internal static let capabilities = L10n.tr("Localizable", "capabilities", fallback: "Capabilities") internal static let capabilities = L10n.tr("Localizable", "capabilities", fallback: "Capabilities")
/// Capsule
internal static let capsule = L10n.tr("Localizable", "capsule", fallback: "Capsule")
/// Cast & Crew /// Cast & Crew
internal static let castAndCrew = L10n.tr("Localizable", "castAndCrew", fallback: "Cast & Crew") internal static let castAndCrew = L10n.tr("Localizable", "castAndCrew", fallback: "Cast & Crew")
/// Category /// Category
internal static let category = L10n.tr("Localizable", "category", fallback: "Category") internal static let category = L10n.tr("Localizable", "category", fallback: "Category")
/// Change Pin /// Change Pin
internal static let changePin = L10n.tr("Localizable", "changePin", fallback: "Change Pin") internal static let changePin = L10n.tr("Localizable", "changePin", fallback: "Change Pin")
/// Channel display
internal static let channelDisplay = L10n.tr("Localizable", "channelDisplay", fallback: "Channel display")
/// Channels /// Channels
internal static let channels = L10n.tr("Localizable", "channels", fallback: "Channels") internal static let channels = L10n.tr("Localizable", "channels", fallback: "Channels")
/// Chapter /// Chapter
@ -282,6 +290,10 @@ internal enum L10n {
internal static let colorist = L10n.tr("Localizable", "colorist", fallback: "Colorist") internal static let colorist = L10n.tr("Localizable", "colorist", fallback: "Colorist")
/// Columns /// Columns
internal static let columns = L10n.tr("Localizable", "columns", fallback: "Columns") internal static let columns = L10n.tr("Localizable", "columns", fallback: "Columns")
/// Columns: %@
internal static func columnsWithCount(_ p1: Any) -> String {
return L10n.tr("Localizable", "columnsWithCount", String(describing: p1), fallback: "Columns: %@")
}
/// Community /// Community
internal static let community = L10n.tr("Localizable", "community", fallback: "Community") internal static let community = L10n.tr("Localizable", "community", fallback: "Community")
/// Community rating /// Community rating
@ -304,6 +316,10 @@ internal enum L10n {
internal static let conductor = L10n.tr("Localizable", "conductor", fallback: "Conductor") internal static let conductor = L10n.tr("Localizable", "conductor", fallback: "Conductor")
/// Confirm /// Confirm
internal static let confirm = L10n.tr("Localizable", "confirm", fallback: "Confirm") internal static let confirm = L10n.tr("Localizable", "confirm", fallback: "Confirm")
/// Are you sure you want to delete %@ and all of its connected users?
internal static func confirmDeleteServerAndUsers(_ p1: Any) -> String {
return L10n.tr("Localizable", "confirmDeleteServerAndUsers", String(describing: p1), fallback: "Are you sure you want to delete %@ and all of its connected users?")
}
/// Confirm New Password /// Confirm New Password
internal static let confirmNewPassword = L10n.tr("Localizable", "confirmNewPassword", fallback: "Confirm New Password") internal static let confirmNewPassword = L10n.tr("Localizable", "confirmNewPassword", fallback: "Confirm New Password")
/// Confirm Password /// Confirm Password
@ -408,6 +424,8 @@ internal enum L10n {
internal static let dayOfWeek = L10n.tr("Localizable", "dayOfWeek", fallback: "Day of Week") internal static let dayOfWeek = L10n.tr("Localizable", "dayOfWeek", fallback: "Day of Week")
/// Days /// Days
internal static let days = L10n.tr("Localizable", "days", fallback: "Days") internal static let days = L10n.tr("Localizable", "days", fallback: "Days")
/// Decrease playback speed
internal static let decreasePlaybackSpeed = L10n.tr("Localizable", "decreasePlaybackSpeed", fallback: "Decrease playback speed")
/// Default /// Default
internal static let `default` = L10n.tr("Localizable", "default", fallback: "Default") internal static let `default` = L10n.tr("Localizable", "default", fallback: "Default")
/// Admins are locked out after 5 failed attempts. Non-admins are locked out after 3 attempts. /// Admins are locked out after 5 failed attempts. Non-admins are locked out after 3 attempts.
@ -482,12 +500,18 @@ internal enum L10n {
internal static let deletion = L10n.tr("Localizable", "deletion", fallback: "Deletion") internal static let deletion = L10n.tr("Localizable", "deletion", fallback: "Deletion")
/// Delivery /// Delivery
internal static let delivery = L10n.tr("Localizable", "delivery", fallback: "Delivery") internal static let delivery = L10n.tr("Localizable", "delivery", fallback: "Delivery")
/// Descending
internal static let descending = L10n.tr("Localizable", "descending", fallback: "Descending")
/// Detailed
internal static let detailed = L10n.tr("Localizable", "detailed", fallback: "Detailed")
/// Details /// Details
internal static let details = L10n.tr("Localizable", "details", fallback: "Details") internal static let details = L10n.tr("Localizable", "details", fallback: "Details")
/// Device /// Device
internal static let device = L10n.tr("Localizable", "device", fallback: "Device") internal static let device = L10n.tr("Localizable", "device", fallback: "Device")
/// Device Access /// Device Access
internal static let deviceAccess = L10n.tr("Localizable", "deviceAccess", fallback: "Device Access") internal static let deviceAccess = L10n.tr("Localizable", "deviceAccess", fallback: "Device Access")
/// Device authentication
internal static let deviceAuth = L10n.tr("Localizable", "deviceAuth", fallback: "Device authentication")
/// Device authentication failed /// Device authentication failed
internal static let deviceAuthFailed = L10n.tr("Localizable", "deviceAuthFailed", fallback: "Device authentication failed") internal static let deviceAuthFailed = L10n.tr("Localizable", "deviceAuthFailed", fallback: "Device authentication failed")
/// Device Profile /// Device Profile
@ -540,8 +564,8 @@ internal enum L10n {
internal static let dvd = L10n.tr("Localizable", "dvd", fallback: "DVD") internal static let dvd = L10n.tr("Localizable", "dvd", fallback: "DVD")
/// Edit /// Edit
internal static let edit = L10n.tr("Localizable", "edit", fallback: "Edit") internal static let edit = L10n.tr("Localizable", "edit", fallback: "Edit")
/// Edit collections /// Edit Collections
internal static let editCollections = L10n.tr("Localizable", "editCollections", fallback: "Edit collections") internal static let editCollections = L10n.tr("Localizable", "editCollections", fallback: "Edit Collections")
/// Edit media /// Edit media
internal static let editMedia = L10n.tr("Localizable", "editMedia", fallback: "Edit media") internal static let editMedia = L10n.tr("Localizable", "editMedia", fallback: "Edit media")
/// Editor /// Editor
@ -648,8 +672,14 @@ internal enum L10n {
internal static let genres = L10n.tr("Localizable", "genres", fallback: "Genres") internal static let genres = L10n.tr("Localizable", "genres", fallback: "Genres")
/// Categories that describe the themes or styles of media. /// Categories that describe the themes or styles of media.
internal static let genresDescription = L10n.tr("Localizable", "genresDescription", fallback: "Categories that describe the themes or styles of media.") internal static let genresDescription = L10n.tr("Localizable", "genresDescription", fallback: "Categories that describe the themes or styles of media.")
/// Gesture lock
internal static let gestureLock = L10n.tr("Localizable", "gestureLock", fallback: "Gesture lock")
/// Gestures /// Gestures
internal static let gestures = L10n.tr("Localizable", "gestures", fallback: "Gestures") internal static let gestures = L10n.tr("Localizable", "gestures", fallback: "Gestures")
/// Gestures locked
internal static let gesturesLocked = L10n.tr("Localizable", "gesturesLocked", fallback: "Gestures locked")
/// Gestures unlocked
internal static let gesturesUnlocked = L10n.tr("Localizable", "gesturesUnlocked", fallback: "Gestures unlocked")
/// Gbps /// Gbps
internal static let gigabitsPerSecond = L10n.tr("Localizable", "gigabitsPerSecond", fallback: "Gbps") internal static let gigabitsPerSecond = L10n.tr("Localizable", "gigabitsPerSecond", fallback: "Gbps")
/// Green /// Green
@ -690,6 +720,12 @@ internal enum L10n {
internal static let images = L10n.tr("Localizable", "images", fallback: "Images") internal static let images = L10n.tr("Localizable", "images", fallback: "Images")
/// Image source /// Image source
internal static let imageSource = L10n.tr("Localizable", "imageSource", fallback: "Image source") internal static let imageSource = L10n.tr("Localizable", "imageSource", fallback: "Image source")
/// Incorrect pin for %@
internal static func incorrectPinForUser(_ p1: Any) -> String {
return L10n.tr("Localizable", "incorrectPinForUser", String(describing: p1), fallback: "Incorrect pin for %@")
}
/// Increase playback speed
internal static let increasePlaybackSpeed = L10n.tr("Localizable", "increasePlaybackSpeed", fallback: "Increase playback speed")
/// Index /// Index
internal static let index = L10n.tr("Localizable", "index", fallback: "Index") internal static let index = L10n.tr("Localizable", "index", fallback: "Index")
/// Index number /// Index number
@ -732,8 +768,12 @@ internal enum L10n {
internal static let kids = L10n.tr("Localizable", "kids", fallback: "Kids") internal static let kids = L10n.tr("Localizable", "kids", fallback: "Kids")
/// kbps /// kbps
internal static let kilobitsPerSecond = L10n.tr("Localizable", "kilobitsPerSecond", fallback: "kbps") internal static let kilobitsPerSecond = L10n.tr("Localizable", "kilobitsPerSecond", fallback: "kbps")
/// Landscape
internal static let landscape = L10n.tr("Localizable", "landscape", fallback: "Landscape")
/// Language /// Language
internal static let language = L10n.tr("Localizable", "language", fallback: "Language") internal static let language = L10n.tr("Localizable", "language", fallback: "Language")
/// Large
internal static let large = L10n.tr("Localizable", "large", fallback: "Large")
/// Larger /// Larger
internal static let larger = L10n.tr("Localizable", "larger", fallback: "Larger") internal static let larger = L10n.tr("Localizable", "larger", fallback: "Larger")
/// Largest /// Largest
@ -752,8 +792,8 @@ internal enum L10n {
} }
/// Layout /// Layout
internal static let layout = L10n.tr("Localizable", "layout", fallback: "Layout") internal static let layout = L10n.tr("Localizable", "layout", fallback: "Layout")
/// Learn more... /// Learn more
internal static let learnMoreEllipsis = L10n.tr("Localizable", "learnMoreEllipsis", fallback: "Learn more...") internal static let learnMore = L10n.tr("Localizable", "learnMore", fallback: "Learn more")
/// Left /// Left
internal static let `left` = L10n.tr("Localizable", "left", fallback: "Left") internal static let `left` = L10n.tr("Localizable", "left", fallback: "Left")
/// Left vertical pan /// Left vertical pan
@ -766,6 +806,8 @@ internal enum L10n {
internal static let letterPicker = L10n.tr("Localizable", "letterPicker", fallback: "Letter Picker") internal static let letterPicker = L10n.tr("Localizable", "letterPicker", fallback: "Letter Picker")
/// Level /// Level
internal static let level = L10n.tr("Localizable", "level", fallback: "Level") internal static let level = L10n.tr("Localizable", "level", fallback: "Level")
/// Libraries
internal static let libraries = L10n.tr("Localizable", "libraries", fallback: "Libraries")
/// Library /// Library
internal static let library = L10n.tr("Localizable", "library", fallback: "Library") internal static let library = L10n.tr("Localizable", "library", fallback: "Library")
/// Light /// Light
@ -874,6 +916,8 @@ internal enum L10n {
internal static let mvc = L10n.tr("Localizable", "mvc", fallback: "MVC") internal static let mvc = L10n.tr("Localizable", "mvc", fallback: "MVC")
/// Name /// Name
internal static let name = L10n.tr("Localizable", "name", fallback: "Name") internal static let name = L10n.tr("Localizable", "name", fallback: "Name")
/// Native
internal static let native = L10n.tr("Localizable", "native", fallback: "Native")
/// Native Player /// Native Player
internal static let nativePlayer = L10n.tr("Localizable", "nativePlayer", fallback: "Native Player") internal static let nativePlayer = L10n.tr("Localizable", "nativePlayer", fallback: "Native Player")
/// Network timed out /// Network timed out
@ -970,6 +1014,8 @@ internal enum L10n {
internal static let passwordChangeWarning = L10n.tr("Localizable", "passwordChangeWarning", fallback: "Changes the Jellyfin server user password. This does not change any Swiftfin settings.") internal static let passwordChangeWarning = L10n.tr("Localizable", "passwordChangeWarning", fallback: "Changes the Jellyfin server user password. This does not change any Swiftfin settings.")
/// New passwords do not match. /// New passwords do not match.
internal static let passwordsDoNotMatch = L10n.tr("Localizable", "passwordsDoNotMatch", fallback: "New passwords do not match.") internal static let passwordsDoNotMatch = L10n.tr("Localizable", "passwordsDoNotMatch", fallback: "New passwords do not match.")
/// Pause
internal static let pause = L10n.tr("Localizable", "pause", fallback: "Pause")
/// Pause on background /// Pause on background
internal static let pauseOnBackground = L10n.tr("Localizable", "pauseOnBackground", fallback: "Pause on background") internal static let pauseOnBackground = L10n.tr("Localizable", "pauseOnBackground", fallback: "Pause on background")
/// Penciller /// Penciller
@ -1008,6 +1054,8 @@ internal enum L10n {
internal static let playOnActive = L10n.tr("Localizable", "playOnActive", fallback: "Play on active") internal static let playOnActive = L10n.tr("Localizable", "playOnActive", fallback: "Play on active")
/// Play Previous Item /// Play Previous Item
internal static let playPreviousItem = L10n.tr("Localizable", "playPreviousItem", fallback: "Play Previous Item") internal static let playPreviousItem = L10n.tr("Localizable", "playPreviousItem", fallback: "Play Previous Item")
/// Portrait
internal static let portrait = L10n.tr("Localizable", "portrait", fallback: "Portrait")
/// Posters /// Posters
internal static let posters = L10n.tr("Localizable", "posters", fallback: "Posters") internal static let posters = L10n.tr("Localizable", "posters", fallback: "Posters")
/// Premiere Date /// Premiere Date
@ -1108,6 +1156,8 @@ internal enum L10n {
internal static let remux = L10n.tr("Localizable", "remux", fallback: "Remux") internal static let remux = L10n.tr("Localizable", "remux", fallback: "Remux")
/// Reorder /// Reorder
internal static let reorder = L10n.tr("Localizable", "reorder", fallback: "Reorder") internal static let reorder = L10n.tr("Localizable", "reorder", fallback: "Reorder")
/// Replace
internal static let replace = L10n.tr("Localizable", "replace", fallback: "Replace")
/// Replace All /// Replace All
internal static let replaceAll = L10n.tr("Localizable", "replaceAll", fallback: "Replace All") internal static let replaceAll = L10n.tr("Localizable", "replaceAll", fallback: "Replace All")
/// Replace all unlocked metadata and images with new information. /// Replace all unlocked metadata and images with new information.
@ -1140,6 +1190,8 @@ internal enum L10n {
internal static let resetAllSettings = L10n.tr("Localizable", "resetAllSettings", fallback: "Reset all settings back to defaults.") internal static let resetAllSettings = L10n.tr("Localizable", "resetAllSettings", fallback: "Reset all settings back to defaults.")
/// Reset the filter values to none. /// Reset the filter values to none.
internal static let resetFilterFooter = L10n.tr("Localizable", "resetFilterFooter", fallback: "Reset the filter values to none.") internal static let resetFilterFooter = L10n.tr("Localizable", "resetFilterFooter", fallback: "Reset the filter values to none.")
/// Reset playback speed
internal static let resetPlaybackSpeed = L10n.tr("Localizable", "resetPlaybackSpeed", fallback: "Reset playback speed")
/// Reset Settings /// Reset Settings
internal static let resetSettings = L10n.tr("Localizable", "resetSettings", fallback: "Reset Settings") internal static let resetSettings = L10n.tr("Localizable", "resetSettings", fallback: "Reset Settings")
/// Reset Swiftfin user settings /// Reset Swiftfin user settings
@ -1194,6 +1246,8 @@ internal enum L10n {
internal static let score = L10n.tr("Localizable", "score", fallback: "Score") internal static let score = L10n.tr("Localizable", "score", fallback: "Score")
/// Screenshot /// Screenshot
internal static let screenshot = L10n.tr("Localizable", "screenshot", fallback: "Screenshot") internal static let screenshot = L10n.tr("Localizable", "screenshot", fallback: "Screenshot")
/// Scrub
internal static let scrub = L10n.tr("Localizable", "scrub", fallback: "Scrub")
/// Scrub Current Time /// Scrub Current Time
internal static let scrubCurrentTime = L10n.tr("Localizable", "scrubCurrentTime", fallback: "Scrub Current Time") internal static let scrubCurrentTime = L10n.tr("Localizable", "scrubCurrentTime", fallback: "Scrub Current Time")
/// Search /// Search
@ -1304,6 +1358,8 @@ internal enum L10n {
internal static let sliderColor = L10n.tr("Localizable", "sliderColor", fallback: "Slider Color") internal static let sliderColor = L10n.tr("Localizable", "sliderColor", fallback: "Slider Color")
/// Slider Type /// Slider Type
internal static let sliderType = L10n.tr("Localizable", "sliderType", fallback: "Slider Type") internal static let sliderType = L10n.tr("Localizable", "sliderType", fallback: "Slider Type")
/// Slow scrub
internal static let slowScrub = L10n.tr("Localizable", "slowScrub", fallback: "Slow scrub")
/// Smaller /// Smaller
internal static let smaller = L10n.tr("Localizable", "smaller", fallback: "Smaller") internal static let smaller = L10n.tr("Localizable", "smaller", fallback: "Smaller")
/// Smallest /// Smallest
@ -1322,6 +1378,8 @@ internal enum L10n {
internal static let splashscreen = L10n.tr("Localizable", "splashscreen", fallback: "Splashscreen") internal static let splashscreen = L10n.tr("Localizable", "splashscreen", fallback: "Splashscreen")
/// When All Servers is selected, use the splashscreen from a single server or a random server /// When All Servers is selected, use the splashscreen from a single server or a random server
internal static let splashscreenFooter = L10n.tr("Localizable", "splashscreenFooter", fallback: "When All Servers is selected, use the splashscreen from a single server or a random server") internal static let splashscreenFooter = L10n.tr("Localizable", "splashscreenFooter", fallback: "When All Servers is selected, use the splashscreen from a single server or a random server")
/// Split
internal static let split = L10n.tr("Localizable", "split", fallback: "Split")
/// Sports /// Sports
internal static let sports = L10n.tr("Localizable", "sports", fallback: "Sports") internal static let sports = L10n.tr("Localizable", "sports", fallback: "Sports")
/// Start date /// Start date
@ -1408,8 +1466,12 @@ internal enum L10n {
internal static let themeVideo = L10n.tr("Localizable", "themeVideo", fallback: "Theme Video") internal static let themeVideo = L10n.tr("Localizable", "themeVideo", fallback: "Theme Video")
/// Thumb /// Thumb
internal static let thumb = L10n.tr("Localizable", "thumb", fallback: "Thumb") internal static let thumb = L10n.tr("Localizable", "thumb", fallback: "Thumb")
/// Thumb
internal static let thumbSlider = L10n.tr("Localizable", "thumbSlider", fallback: "Thumb")
/// Time /// Time
internal static let time = L10n.tr("Localizable", "time", fallback: "Time") internal static let time = L10n.tr("Localizable", "time", fallback: "Time")
/// Time left
internal static let timeLeft = L10n.tr("Localizable", "timeLeft", fallback: "Time left")
/// Time Limit /// Time Limit
internal static let timeLimit = L10n.tr("Localizable", "timeLimit", fallback: "Time Limit") internal static let timeLimit = L10n.tr("Localizable", "timeLimit", fallback: "Time Limit")
/// Time limit: %1$@ /// Time limit: %1$@
@ -1422,6 +1484,8 @@ internal enum L10n {
internal static let timestampType = L10n.tr("Localizable", "timestampType", fallback: "Timestamp Type") internal static let timestampType = L10n.tr("Localizable", "timestampType", fallback: "Timestamp Type")
/// Title /// Title
internal static let title = L10n.tr("Localizable", "title", fallback: "Title") internal static let title = L10n.tr("Localizable", "title", fallback: "Title")
/// Total time
internal static let totalTime = L10n.tr("Localizable", "totalTime", fallback: "Total time")
/// Trailer /// Trailer
internal static let trailer = L10n.tr("Localizable", "trailer", fallback: "Trailer") internal static let trailer = L10n.tr("Localizable", "trailer", fallback: "Trailer")
/// Trailers /// Trailers
@ -1456,6 +1520,8 @@ internal enum L10n {
internal static let unableToPerformDeviceAuth = L10n.tr("Localizable", "unableToPerformDeviceAuth", fallback: "Unable to perform device authentication") internal static let unableToPerformDeviceAuth = L10n.tr("Localizable", "unableToPerformDeviceAuth", fallback: "Unable to perform device authentication")
/// Unable to perform device authentication. You may need to enable Face ID in the Settings app for Swiftfin. /// Unable to perform device authentication. You may need to enable Face ID in the Settings app for Swiftfin.
internal static let unableToPerformDeviceAuthFaceID = L10n.tr("Localizable", "unableToPerformDeviceAuthFaceID", fallback: "Unable to perform device authentication. You may need to enable Face ID in the Settings app for Swiftfin.") internal static let unableToPerformDeviceAuthFaceID = L10n.tr("Localizable", "unableToPerformDeviceAuthFaceID", fallback: "Unable to perform device authentication. You may need to enable Face ID in the Settings app for Swiftfin.")
/// Unable to update custom name
internal static let unableToUpdateCustomName = L10n.tr("Localizable", "unableToUpdateCustomName", fallback: "Unable to update custom name")
/// Unaired /// Unaired
internal static let unaired = L10n.tr("Localizable", "unaired", fallback: "Unaired") internal static let unaired = L10n.tr("Localizable", "unaired", fallback: "Unaired")
/// Unauthorized /// Unauthorized
@ -1546,6 +1612,8 @@ internal enum L10n {
internal static let videoTranscoding = L10n.tr("Localizable", "videoTranscoding", fallback: "Video transcoding") internal static let videoTranscoding = L10n.tr("Localizable", "videoTranscoding", fallback: "Video transcoding")
/// Some views may need an app restart to update. /// Some views may need an app restart to update.
internal static let viewsMayRequireRestart = L10n.tr("Localizable", "viewsMayRequireRestart", fallback: "Some views may need an app restart to update.") internal static let viewsMayRequireRestart = L10n.tr("Localizable", "viewsMayRequireRestart", fallback: "Some views may need an app restart to update.")
/// Volume
internal static let volume = L10n.tr("Localizable", "volume", fallback: "Volume")
/// Votes /// Votes
internal static let votes = L10n.tr("Localizable", "votes", fallback: "Votes") internal static let votes = L10n.tr("Localizable", "votes", fallback: "Votes")
/// Weekday /// Weekday

View File

@ -68,7 +68,7 @@ final class DeviceDetailViewModel: ViewModel, Stateful, Eventful {
} }
} catch { } catch {
await MainActor.run { await MainActor.run {
self.eventSubject.send(.error(.init("Unable to update custom name"))) self.eventSubject.send(.error(.init(L10n.unableToUpdateCustomName)))
} }
} }

View File

@ -77,8 +77,7 @@ final class SelectUserViewModel: ViewModel, Eventful, Stateful {
if user.accessPolicy == .requirePin, let storedPin = keychain.get("\(user.id)-pin") { if user.accessPolicy == .requirePin, let storedPin = keychain.get("\(user.id)-pin") {
if pin != storedPin { if pin != storedPin {
eventSubject.send(.error(.init("Incorrect pin for \(user.username)"))) eventSubject.send(.error(.init(L10n.incorrectPinForUser(user.username))))
return .content return .content
} }
} }

View File

@ -61,7 +61,7 @@ final class UserLocalSecurityViewModel: ViewModel, Eventful {
if let storedPin = keychain.get("\(userSession.user.id)-pin") { if let storedPin = keychain.get("\(userSession.user.id)-pin") {
if oldPin != storedPin { if oldPin != storedPin {
eventSubject.send(.error(.init("Incorrect pin for \(userSession.user.username)"))) eventSubject.send(.error(.init(L10n.incorrectPinForUser(userSession.user.username))))
throw JellyfinAPIError("invalid pin") throw JellyfinAPIError("invalid pin")
} }
} }

View File

@ -85,7 +85,7 @@ struct EditServerView: View {
router.popLast() router.popLast()
} }
} message: { } message: {
Text("Are you sure you want to delete \(viewModel.server.name) and all of its connected users?") Text(L10n.confirmDeleteServerAndUsers(viewModel.server.name))
} }
} }
} }

View File

@ -26,7 +26,7 @@ struct LearnMoreButton: View {
// MARK: - Body // MARK: - Body
var body: some View { var body: some View {
Button(L10n.learnMoreEllipsis) { Button(L10n.learnMore + "\u{2026}") {
isPresented = true isPresented = true
} }
.foregroundStyle(Color.accentColor) .foregroundStyle(Color.accentColor)

View File

@ -33,7 +33,7 @@ struct ListTitleSection: View {
} }
if let onLearnMore { if let onLearnMore {
Button("Learn More\u{2026}", action: onLearnMore) Button(L10n.learnMore + "\u{2026}", action: onLearnMore)
} }
} }
.font(.subheadline) .font(.subheadline)
@ -99,7 +99,7 @@ struct InsetGroupedListHeader<Content: View>: View {
} }
if onLearnMore != nil { if onLearnMore != nil {
Text("Learn More\u{2026}") Text(L10n.learnMore + "\u{2026}")
.foregroundStyle(accentColor) .foregroundStyle(accentColor)
} }
} }

View File

@ -163,12 +163,12 @@ struct ChannelLibraryView: View {
Menu { Menu {
// We repurposed `LibraryDisplayType` but want different labels // We repurposed `LibraryDisplayType` but want different labels
Picker("Channel Display", selection: $channelDisplayType) { Picker(L10n.channelDisplay, selection: $channelDisplayType) {
Label(L10n.compact, systemImage: LibraryDisplayType.grid.systemImage) Label(L10n.compact, systemImage: LibraryDisplayType.grid.systemImage)
.tag(LibraryDisplayType.grid) .tag(LibraryDisplayType.grid)
Label("Detailed", systemImage: LibraryDisplayType.list.systemImage) Label(L10n.detailed, systemImage: LibraryDisplayType.list.systemImage)
.tag(LibraryDisplayType.list) .tag(LibraryDisplayType.list)
} }
} label: { } label: {

View File

@ -72,7 +72,7 @@ struct EditServerView: View {
router.popLast() router.popLast()
} }
} message: { } message: {
Text("Are you sure you want to delete \(viewModel.server.name) and all of its connected users?") Text(L10n.confirmDeleteServerAndUsers(viewModel.server.name))
} }
} }
} }

View File

@ -37,14 +37,14 @@ extension PagingLibraryView {
var body: some View { var body: some View {
Menu { Menu {
Section("Poster") { Section(L10n.posters) {
Button { Button {
posterType = .landscape posterType = .landscape
} label: { } label: {
if posterType == .landscape { if posterType == .landscape {
Label("Landscape", systemImage: "checkmark") Label(L10n.landscape, systemImage: "checkmark")
} else { } else {
Label("Landscape", systemImage: "rectangle") Label(L10n.landscape, systemImage: "rectangle")
} }
} }
@ -52,9 +52,9 @@ extension PagingLibraryView {
posterType = .portrait posterType = .portrait
} label: { } label: {
if posterType == .portrait { if posterType == .portrait {
Label("Portrait", systemImage: "checkmark") Label(L10n.portrait, systemImage: "checkmark")
} else { } else {
Label("Portrait", systemImage: "rectangle.portrait") Label(L10n.portrait, systemImage: "rectangle.portrait")
} }
} }
} }
@ -82,7 +82,7 @@ extension PagingLibraryView {
} }
if viewType == .list, UIDevice.isPad { if viewType == .list, UIDevice.isPad {
Stepper("Columns: \(listColumnCount)", value: $listColumnCount, in: 1 ... 3) Stepper(L10n.columnsWithCount(listColumnCount), value: $listColumnCount, in: 1 ... 3)
} }
} label: { } label: {
switch viewType { switch viewType {

View File

@ -140,7 +140,7 @@ struct CustomizeViewsSettings: View {
CaseIterablePicker(L10n.search, selection: $searchPosterType) CaseIterablePicker(L10n.search, selection: $searchPosterType)
} }
Section("Libraries") { Section(L10n.libraries) {
CaseIterablePicker(L10n.library, selection: $libraryDisplayType) CaseIterablePicker(L10n.library, selection: $libraryDisplayType)
CaseIterablePicker(L10n.posters, selection: $libraryPosterType) CaseIterablePicker(L10n.posters, selection: $libraryPosterType)

View File

@ -49,7 +49,7 @@ extension UserSignInView {
VStack(alignment: .leading, spacing: 10) { VStack(alignment: .leading, spacing: 10) {
Text( Text(
"Additional security for users signed in to this device. This does not change any Jellyfin server user settings." L10n.additionalSecurityAccessDescription
) )
// frame necessary with bug within BulletedList // frame necessary with bug within BulletedList

View File

@ -188,9 +188,9 @@ struct LiveVideoPlayer: View {
} }
.onChange(of: isGestureLocked) { newValue in .onChange(of: isGestureLocked) { newValue in
if newValue { if newValue {
updateViewProxy.present(systemName: "lock.fill", title: "Gestures Locked") updateViewProxy.present(systemName: "lock.fill", title: L10n.gesturesLocked)
} else { } else {
updateViewProxy.present(systemName: "lock.open.fill", title: "Gestures Unlocked") updateViewProxy.present(systemName: "lock.open.fill", title: L10n.gesturesUnlocked)
} }
} }
.onChange(of: isScrubbing) { newValue in .onChange(of: isScrubbing) { newValue in
@ -305,7 +305,7 @@ extension LiveVideoPlayer {
private func handleTapGesture(unitPoint: UnitPoint, taps: Int) { private func handleTapGesture(unitPoint: UnitPoint, taps: Int) {
guard !isGestureLocked else { guard !isGestureLocked else {
updateViewProxy.present(systemName: "lock.fill", title: "Gestures Locked") updateViewProxy.present(systemName: "lock.fill", title: L10n.gesturesLocked)
return return
} }
@ -330,7 +330,7 @@ extension LiveVideoPlayer {
private func handleDoubleTouchGesture(unitPoint: UnitPoint, taps: Int) { private func handleDoubleTouchGesture(unitPoint: UnitPoint, taps: Int) {
guard !isGestureLocked else { guard !isGestureLocked else {
updateViewProxy.present(systemName: "lock.fill", title: "Gestures Locked") updateViewProxy.present(systemName: "lock.fill", title: L10n.gesturesLocked)
return return
} }

View File

@ -55,10 +55,10 @@ struct VideoPlayerKeyCommandsModifier: ViewModifier {
) { ) {
if videoPlayerManager.state == .playing { if videoPlayerManager.state == .playing {
videoPlayerManager.proxy.pause() videoPlayerManager.proxy.pause()
updateViewProxy.present(systemName: "pause.fill", title: "Pause") updateViewProxy.present(systemName: "pause.fill", title: L10n.pause)
} else { } else {
videoPlayerManager.proxy.play() videoPlayerManager.proxy.play()
updateViewProxy.present(systemName: "play.fill", title: "Play") updateViewProxy.present(systemName: "play.fill", title: L10n.play)
} }
} }
@ -139,7 +139,7 @@ struct VideoPlayerKeyCommandsModifier: ViewModifier {
// MARK: aspect fill // MARK: aspect fill
KeyCommandAction( KeyCommandAction(
title: "Aspect Fill", title: L10n.aspectFill,
input: "f", input: "f",
modifierFlags: .command modifierFlags: .command
) { ) {
@ -151,7 +151,7 @@ struct VideoPlayerKeyCommandsModifier: ViewModifier {
// MARK: decrease playback speed // MARK: decrease playback speed
KeyCommandAction( KeyCommandAction(
title: "Decrease Playback Speed", title: L10n.decreasePlaybackSpeed,
input: "[", input: "[",
modifierFlags: .command modifierFlags: .command
) { ) {
@ -171,7 +171,7 @@ struct VideoPlayerKeyCommandsModifier: ViewModifier {
// MARK: increase playback speed // MARK: increase playback speed
KeyCommandAction( KeyCommandAction(
title: "Increase Playback Speed", title: L10n.increasePlaybackSpeed,
input: "]", input: "]",
modifierFlags: .command modifierFlags: .command
) { ) {
@ -191,7 +191,7 @@ struct VideoPlayerKeyCommandsModifier: ViewModifier {
// MARK: reset playback speed // MARK: reset playback speed
KeyCommandAction( KeyCommandAction(
title: "Reset Playback Speed", title: L10n.resetPlaybackSpeed,
input: "\\", input: "\\",
modifierFlags: .command modifierFlags: .command
) { ) {

View File

@ -225,9 +225,9 @@ struct VideoPlayer: View {
} }
.onChange(of: isGestureLocked) { newValue in .onChange(of: isGestureLocked) { newValue in
if newValue { if newValue {
updateViewProxy.present(systemName: "lock.fill", title: "Gestures Locked") updateViewProxy.present(systemName: "lock.fill", title: L10n.gesturesLocked)
} else { } else {
updateViewProxy.present(systemName: "lock.open.fill", title: "Gestures Unlocked") updateViewProxy.present(systemName: "lock.open.fill", title: L10n.gesturesUnlocked)
} }
} }
.onChange(of: isScrubbing) { newValue in .onChange(of: isScrubbing) { newValue in
@ -352,7 +352,7 @@ extension VideoPlayer {
private func handleTapGesture(unitPoint: UnitPoint, taps: Int) { private func handleTapGesture(unitPoint: UnitPoint, taps: Int) {
guard !isGestureLocked else { guard !isGestureLocked else {
updateViewProxy.present(systemName: "lock.fill", title: "Gestures Locked") updateViewProxy.present(systemName: "lock.fill", title: L10n.gesturesLocked)
return return
} }
@ -382,7 +382,7 @@ extension VideoPlayer {
} }
guard !isGestureLocked else { guard !isGestureLocked else {
updateViewProxy.present(systemName: "lock.fill", title: "Gestures Locked") updateViewProxy.present(systemName: "lock.fill", title: L10n.gesturesLocked)
return return
} }