Public Testflight update? (#194)

* fxied trackers text

* Update SettingsViewTrackers.swift

* Update SettingsViewGeneral.swift

* Languages fix + Arabic + French + disable flip by Arabic (#193)

* fixed tmp folder issues

* 😭

* yeah

* ok well lets test

---------

Co-authored-by: 50/50 <80717571+50n50@users.noreply.github.com>
This commit is contained in:
cranci 2025-06-15 10:53:31 +02:00 committed by GitHub
parent 0f8acca4df
commit 862286840f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
27 changed files with 2010 additions and 122 deletions

View file

@ -7,6 +7,8 @@
import UIKit
import AVKit
import Combine
import GroupActivities
class VideoPlayerViewController: UIViewController {
let module: ScrapingModule
@ -29,6 +31,9 @@ class VideoPlayerViewController: UIViewController {
var subtitlesLoader: VTTSubtitlesLoader?
var subtitleLabel: UILabel?
private var sharePlayCoordinator: SharePlayCoordinator?
private var subscriptions = Set<AnyCancellable>()
private var aniListUpdateSent = false
private var aniListUpdatedSuccessfully = false
private var traktUpdateSent = false
@ -40,6 +45,7 @@ class VideoPlayerViewController: UIViewController {
if UserDefaults.standard.object(forKey: "subtitlesEnabled") == nil {
UserDefaults.standard.set(true, forKey: "subtitlesEnabled")
}
setupSharePlay()
}
required init?(coder: NSCoder) {
@ -129,6 +135,10 @@ class VideoPlayerViewController: UIViewController {
if !subtitles.isEmpty && UserDefaults.standard.bool(forKey: "subtitlesEnabled") {
setupSubtitles()
}
// Configure SharePlay after player setup
setupSharePlayButton(in: playerViewController)
configureSharePlayForPlayer()
}
addPeriodicTimeObserver(fullURL: fullUrl)
@ -275,6 +285,79 @@ class VideoPlayerViewController: UIViewController {
}
}
@MainActor
private func setupSharePlay() {
sharePlayCoordinator = SharePlayCoordinator()
sharePlayCoordinator?.configureGroupSession()
if let playerViewController = playerViewController {
setupSharePlayButton(in: playerViewController)
}
}
private func setupSharePlayButton(in playerViewController: NormalPlayer) {
// WIP
}
@MainActor
private func startSharePlay() {
guard let streamUrl = streamUrl else { return }
Task {
var episodeImageData: Data?
if !episodeImageUrl.isEmpty, let imageUrl = URL(string: episodeImageUrl) {
episodeImageData = try? await URLSession.shared.data(from: imageUrl).0
}
let activity = VideoWatchingActivity(
mediaTitle: mediaTitle,
episodeNumber: episodeNumber,
streamUrl: streamUrl,
subtitles: subtitles,
aniListID: aniListID,
fullUrl: fullUrl,
headers: headers,
episodeImageUrl: episodeImageUrl,
episodeImageData: episodeImageData,
totalEpisodes: totalEpisodes,
tmdbID: tmdbID,
isMovie: isMovie,
seasonNumber: seasonNumber
)
await sharePlayCoordinator?.startSharePlay(with: activity)
}
}
private func configureSharePlayForPlayer() {
guard let player = player else { return }
sharePlayCoordinator?.coordinatePlayback(with: player)
}
@MainActor
func presentSharePlayInvitation() {
guard let streamUrl = streamUrl else {
Logger.shared.log("Cannot start SharePlay: Stream URL is nil", type: "Error")
return
}
SharePlayManager.shared.presentSharePlayInvitation(
from: self,
mediaTitle: mediaTitle,
episodeNumber: episodeNumber,
streamUrl: streamUrl,
subtitles: subtitles,
aniListID: aniListID,
fullUrl: fullUrl,
headers: headers,
episodeImageUrl: episodeImageUrl,
totalEpisodes: totalEpisodes,
tmdbID: tmdbID,
isMovie: isMovie,
seasonNumber: seasonNumber
)
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
if UserDefaults.standard.bool(forKey: "alwaysLandscape") {
return .landscape
@ -299,5 +382,9 @@ class VideoPlayerViewController: UIViewController {
subtitleLabel?.removeFromSuperview()
subtitleLabel = nil
subtitlesLoader = nil
sharePlayCoordinator?.leaveGroupSession()
sharePlayCoordinator = nil
subscriptions.removeAll()
}
}

View file

@ -0,0 +1,78 @@
//
// SharePlayCoordinator.swift
// Sora
//
// Created by Francesco on 15/06/25.
//
import Combine
import Foundation
import AVFoundation
import GroupActivities
@MainActor
class SharePlayCoordinator: ObservableObject {
private var subscriptions = Set<AnyCancellable>()
private var groupSession: GroupSession<VideoWatchingActivity>?
@Published var isEligibleForGroupSession = false
@Published var groupSessionState: GroupSession<VideoWatchingActivity>.State = .waiting
private var playbackCoordinator: AVPlayerPlaybackCoordinator?
func configureGroupSession() {
Task {
for await session in VideoWatchingActivity.sessions() {
await configureGroupSession(session)
}
}
}
private func configureGroupSession(_ groupSession: GroupSession<VideoWatchingActivity>) async {
self.groupSession = groupSession
groupSession.$state
.receive(on: DispatchQueue.main)
.assign(to: &$groupSessionState)
groupSession.$activeParticipants
.receive(on: DispatchQueue.main)
.sink { participants in
Logger.shared.log("Active participants: \(participants.count)", type: "SharePlay")
}
.store(in: &subscriptions)
groupSession.join()
}
func startSharePlay(with activity: VideoWatchingActivity) async {
do {
_ = try await activity.activate()
Logger.shared.log("SharePlay activity activated successfully", type: "SharePlay")
} catch {
Logger.shared.log("Failed to activate SharePlay: \(error.localizedDescription)", type: "Error")
}
}
func coordinatePlayback(with player: AVPlayer) {
guard let groupSession = groupSession else { return }
playbackCoordinator = player.playbackCoordinator
playbackCoordinator?.coordinateWithSession(groupSession)
Logger.shared.log("Playback coordination established", type: "SharePlay")
}
nonisolated func leaveGroupSession() {
Task { @MainActor in
self.groupSession?.leave()
self.playbackCoordinator = nil
Logger.shared.log("Left SharePlay session", type: "SharePlay")
}
}
deinit {
subscriptions.removeAll()
playbackCoordinator = nil
}
}

View file

@ -0,0 +1,77 @@
//
// SharePlayManager.swift
// Sora
//
// Created by Francesco on 15/06/25.
//
import UIKit
import Foundation
import GroupActivities
class SharePlayManager {
static let shared = SharePlayManager()
private init() {}
func isSharePlayAvailable() -> Bool {
return true
}
func presentSharePlayInvitation(from viewController: UIViewController,
mediaTitle: String,
episodeNumber: Int,
streamUrl: String,
subtitles: String = "",
aniListID: Int = 0,
fullUrl: String,
headers: [String: String]? = nil,
episodeImageUrl: String = "",
totalEpisodes: Int = 0,
tmdbID: Int? = nil,
isMovie: Bool = false,
seasonNumber: Int = 1) {
Task { @MainActor in
var episodeImageData: Data?
if !episodeImageUrl.isEmpty, let imageUrl = URL(string: episodeImageUrl) {
do {
episodeImageData = try await URLSession.shared.data(from: imageUrl).0
} catch {
Logger.shared.log("Failed to load episode image for SharePlay: \(error.localizedDescription)", type: "Error")
}
}
let activity = VideoWatchingActivity(
mediaTitle: mediaTitle,
episodeNumber: episodeNumber,
streamUrl: streamUrl,
subtitles: subtitles,
aniListID: aniListID,
fullUrl: fullUrl,
headers: headers,
episodeImageUrl: episodeImageUrl,
episodeImageData: episodeImageData,
totalEpisodes: totalEpisodes,
tmdbID: tmdbID,
isMovie: isMovie,
seasonNumber: seasonNumber
)
do {
_ = try await activity.activate()
Logger.shared.log("SharePlay invitation sent successfully", type: "SharePlay")
} catch {
Logger.shared.log("Failed to send SharePlay invitation: \(error.localizedDescription)", type: "Error")
let alert = UIAlertController(
title: "SharePlay Unavailable",
message: "SharePlay is not available right now. Make sure you're connected to FaceTime or have SharePlay enabled in Control Center.",
preferredStyle: .alert
)
alert.addAction(UIAlertAction(title: "OK", style: .default))
viewController.present(alert, animated: true)
}
}
}
}

View file

@ -0,0 +1,68 @@
//
// VideoWatchingActivity.swift
// Sora
//
// Created by Francesco on 15/06/25.
//
import UIKit
import Foundation
import GroupActivities
struct VideoWatchingActivity: GroupActivity {
var metadata: GroupActivityMetadata {
var metadata = GroupActivityMetadata()
metadata.title = mediaTitle
metadata.subtitle = "Episode \(episodeNumber)"
if let imageData = episodeImageData,
let uiImage = UIImage(data: imageData) {
metadata.previewImage = uiImage.cgImage
}
metadata.type = .watchTogether
return metadata
}
let mediaTitle: String
let episodeNumber: Int
let streamUrl: String
let subtitles: String
let aniListID: Int
let fullUrl: String
let headers: [String: String]?
let episodeImageUrl: String
let episodeImageData: Data?
let totalEpisodes: Int
let tmdbID: Int?
let isMovie: Bool
let seasonNumber: Int
init(mediaTitle: String,
episodeNumber: Int,
streamUrl: String,
subtitles: String = "",
aniListID: Int = 0,
fullUrl: String,
headers: [String: String]? = nil,
episodeImageUrl: String = "",
episodeImageData: Data? = nil,
totalEpisodes: Int = 0,
tmdbID: Int? = nil,
isMovie: Bool = false,
seasonNumber: Int = 1) {
self.mediaTitle = mediaTitle
self.episodeNumber = episodeNumber
self.streamUrl = streamUrl
self.subtitles = subtitles
self.aniListID = aniListID
self.fullUrl = fullUrl
self.headers = headers
self.episodeImageUrl = episodeImageUrl
self.episodeImageData = episodeImageData
self.totalEpisodes = totalEpisodes
self.tmdbID = tmdbID
self.isMovie = isMovie
self.seasonNumber = seasonNumber
}
}

View file

@ -2,6 +2,10 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.developer.group-session</key>
<true/>
<key>com.apple.developer.group-session.video</key>
<true/>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.assets.movies.read-write</key>

View file

@ -19,6 +19,7 @@ struct SoraApp: App {
if let userAccentColor = UserDefaults.standard.color(forKey: "accentColor") {
UIView.appearance(whenContainedInInstancesOf: [UIAlertController.self]).tintColor = userAccentColor
}
clearTmpFolder()
TraktToken.checkAuthenticationStatus { isAuthenticated in
if isAuthenticated {
@ -38,6 +39,7 @@ struct SoraApp: App {
ContentView()
}
}
.environment(\.layoutDirection, .leftToRight)
.environmentObject(moduleManager)
.environmentObject(settings)
.environmentObject(libraryManager)
@ -102,4 +104,20 @@ struct SoraApp: App {
break
}
}
}
private func clearTmpFolder() {
let fileManager = FileManager.default
let tmpDirectory = NSTemporaryDirectory()
do {
let tmpURL = URL(fileURLWithPath: tmpDirectory)
let tmpContents = try fileManager.contentsOfDirectory(at: tmpURL, includingPropertiesForKeys: nil)
for url in tmpContents {
try fileManager.removeItem(at: url)
}
} catch {
Logger.shared.log("Failed to clear tmp folder: \(error.localizedDescription)", type: "Error")
}
}
}

View file

@ -9,7 +9,6 @@ import Foundation
import SwiftUI
import AVFoundation
struct DownloadRequest {
let url: URL
let headers: [String: String]

View file

@ -1106,6 +1106,7 @@ struct EnhancedShowEpisodesView: View {
}
}
.padding(.vertical)
.scrollViewBottomPadding()
}
.navigationTitle(NSLocalizedString("Episodes", comment: ""))
.navigationBarTitleDisplayMode(.inline)

View file

@ -1280,18 +1280,12 @@ struct MediaInfoView: View {
self.tmdbType = type
tmdbSuccess = true
Logger.shared.log("Successfully fetched TMDB ID: \(id) (type: \(type.rawValue))", type: "Debug")
if self.activeProvider != "TMDB" {
self.fetchTMDBPosterImageAndSet()
}
} else {
Logger.shared.log("Failed to fetch TMDB ID", type: "Debug")
}
checkCompletion()
}
}
fetchAniListIDForSync()
}
private func fetchItemID(byTitle title: String, completion: @escaping (Result<Int, Error>) -> Void) {

View file

@ -141,10 +141,9 @@ struct SettingsViewData: View {
@State private var isCalculatingSize: Bool = false
@State private var cacheSize: Int64 = 0
@State private var documentsSize: Int64 = 0
@State private var downloadsSize: Int64 = 0
enum ActiveAlert {
case eraseData, removeDocs, removeDownloads, clearCache
case eraseData, removeDocs, clearCache
}
@State private var activeAlert: ActiveAlert = .eraseData
@ -154,7 +153,7 @@ struct SettingsViewData: View {
VStack(spacing: 24) {
SettingsSection(
title: NSLocalizedString("App Storage", comment: ""),
footer: NSLocalizedString("The app cache helps the app load images faster.\n\nClearing the Documents folder will delete all downloaded modules.\n\nDo not erase App Data unless you understand the consequences — it may cause the app to malfunction.", comment: "")
footer: NSLocalizedString("The app cache helps the app load images faster.\n\nClearing the Documents folder will delete all downloaded modules.\n\nErasing the App Data will clears all your settings and data of the app.", comment: "")
) {
VStack(spacing: 0) {
SettingsButtonRow(
@ -169,18 +168,6 @@ struct SettingsViewData: View {
Divider().padding(.horizontal, 16)
SettingsButtonRow(
icon: "film",
title: NSLocalizedString("Remove Downloads", comment: ""),
subtitle: formatSize(downloadsSize),
action: {
activeAlert = .removeDownloads
showAlert = true
}
)
Divider().padding(.horizontal, 16)
SettingsButtonRow(
icon: "doc.text",
title: NSLocalizedString("Remove All Documents", comment: ""),
@ -209,7 +196,6 @@ struct SettingsViewData: View {
.onAppear {
calculateCacheSize()
updateSizes()
calculateDownloadsSize()
}
.alert(isPresented: $showAlert) {
switch activeAlert {
@ -231,15 +217,6 @@ struct SettingsViewData: View {
},
secondaryButton: .cancel()
)
case .removeDownloads:
return Alert(
title: Text(NSLocalizedString("Remove Downloaded Media", comment: "")),
message: Text(NSLocalizedString("Are you sure you want to remove all downloaded media files (.mov, .mp4, .pkg)? This action cannot be undone.", comment: "")),
primaryButton: .destructive(Text(NSLocalizedString("Remove", comment: ""))) {
removeDownloadedMedia()
},
secondaryButton: .cancel()
)
case .clearCache:
return Alert(
title: Text(NSLocalizedString("Clear Cache", comment: "")),
@ -286,42 +263,6 @@ struct SettingsViewData: View {
}
}
func calculateDownloadsSize() {
DispatchQueue.global(qos: .background).async {
if let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
let size = calculateMediaFilesSize(in: documentsURL)
DispatchQueue.main.async {
self.downloadsSize = size
}
}
}
}
func calculateMediaFilesSize(in directory: URL) -> Int64 {
let fileManager = FileManager.default
var totalSize: Int64 = 0
let mediaExtensions = [".mov", ".mp4", ".pkg"]
do {
let contents = try fileManager.contentsOfDirectory(at: directory, includingPropertiesForKeys: [.fileSizeKey, .isDirectoryKey])
for url in contents {
let resourceValues = try url.resourceValues(forKeys: [.fileSizeKey, .isDirectoryKey])
if resourceValues.isDirectory == true {
totalSize += calculateMediaFilesSize(in: url)
} else {
let fileExtension = url.pathExtension.lowercased()
if mediaExtensions.contains(".\(fileExtension)") {
totalSize += Int64(resourceValues.fileSize ?? 0)
}
}
}
} catch {
Logger.shared.log("Error calculating media files size: \(error)", type: "Error")
}
return totalSize
}
func clearAllCaches() {
clearCache()
}
@ -337,47 +278,12 @@ struct SettingsViewData: View {
Logger.shared.log("Cache cleared successfully!", type: "General")
calculateCacheSize()
updateSizes()
calculateDownloadsSize()
}
} catch {
Logger.shared.log("Failed to clear cache.", type: "Error")
}
}
func removeDownloadedMedia() {
let fileManager = FileManager.default
let mediaExtensions = [".mov", ".mp4", ".pkg"]
if let documentsURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first {
removeMediaFiles(in: documentsURL, extensions: mediaExtensions)
Logger.shared.log("Downloaded media files removed", type: "General")
updateSizes()
calculateDownloadsSize()
}
}
func removeMediaFiles(in directory: URL, extensions: [String]) {
let fileManager = FileManager.default
do {
let contents = try fileManager.contentsOfDirectory(at: directory, includingPropertiesForKeys: [.isDirectoryKey])
for url in contents {
let resourceValues = try url.resourceValues(forKeys: [.isDirectoryKey])
if resourceValues.isDirectory == true {
removeMediaFiles(in: url, extensions: extensions)
} else {
let fileExtension = ".\(url.pathExtension.lowercased())"
if extensions.contains(fileExtension) {
try fileManager.removeItem(at: url)
Logger.shared.log("Removed media file: \(url.lastPathComponent)", type: "General")
}
}
}
} catch {
Logger.shared.log("Error removing media files in \(directory.path): \(error)", type: "Error")
}
}
func removeAllFilesInDocuments() {
let fileManager = FileManager.default
if let documentsURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first {
@ -431,4 +337,3 @@ struct SettingsViewData: View {
return formatter.string(fromByteCount: bytes)
}
}

View file

@ -202,9 +202,10 @@ struct SettingsViewGeneral: View {
SettingsPickerRow(
icon: "globe",
title: NSLocalizedString("App Language", comment: ""),
options: ["English", "Dutch"],
options: ["English", "Dutch", "French", "Arabic"],
optionToString: { $0 },
selection: $settings.selectedLanguage
selection: $settings.selectedLanguage,
showDivider: false
)
.onChange(of: settings.selectedLanguage) { _ in
showRestartAlert = true

View file

@ -147,7 +147,7 @@ struct SettingsViewTrackers: View {
.frame(height: 18)
} else if isAnilistLoggedIn {
HStack(spacing: 0) {
Text(NSLocalizedString("Logged in as", comment: ""))
Text(NSLocalizedString("Logged in as ", comment: ""))
.font(.footnote)
.foregroundStyle(.gray)
Text(anilistUsername)
@ -240,7 +240,7 @@ struct SettingsViewTrackers: View {
.frame(height: 18)
} else if isTraktLoggedIn {
HStack(spacing: 0) {
Text(NSLocalizedString("Logged in as", comment: ""))
Text(NSLocalizedString("Logged in as ", comment: ""))
.font(.footnote)
.foregroundStyle(.gray)
Text(traktUsername)
@ -270,7 +270,7 @@ struct SettingsViewTrackers: View {
SettingsToggleRow(
icon: "arrow.triangle.2.circlepath",
title: NSLocalizedString("Sync TV shows progress", comment: ""),
title: NSLocalizedString("Sync shows/movies progress", comment: ""),
isOn: $isSendTraktUpdates,
showDivider: false
)

View file

@ -174,7 +174,7 @@ struct SettingsView: View {
Divider().padding(.horizontal, 16)
NavigationLink(destination: SettingsViewDownloads()) {
SettingsNavigationRow(icon: "arrow.down.circle", titleKey: "Download")
SettingsNavigationRow(icon: "arrow.down.circle", titleKey: "Downloads")
}
Divider().padding(.horizontal, 16)
@ -400,7 +400,17 @@ class Settings: ObservableObject {
}
func updateLanguage() {
let languageCode = selectedLanguage == "Dutch" ? "nl" : "en"
let languageCode: String
switch selectedLanguage {
case "Dutch":
languageCode = "nl"
case "French":
languageCode = "fr"
case "Arabic":
languageCode = "ar"
default:
languageCode = "en"
}
UserDefaults.standard.set([languageCode], forKey: "AppleLanguages")
UserDefaults.standard.synchronize()
}

View file

@ -0,0 +1,384 @@
/* General */
"About" = "حول";
"About Sora" = "حول Sora";
"Active" = "نشط";
"Active Downloads" = "التنزيلات النشطة";
"Actively downloading media can be tracked from here." = "يمكن تتبع المحتوى الذي يتم تنزيله حاليًا من هنا.";
"Add Module" = "إضافة وحدة";
"Adjust the number of media items per row in portrait and landscape modes." = "اضبط عدد عناصر المحتوى في كل صف في الوضعين الرأسي والأفقي.";
"Advanced" = "متقدم";
"AKA Sulfur" = "يعرف أيضًا باسم Sulfur";
"All Bookmarks" = "العناصر المحفوظة";
"All Watching" = "الكل قيد المشاهدة";
"Also known as Sulfur" = "يعرف أيضًا باسم Sulfur";
"AniList" = "AniList";
"AniList ID" = "معرّف AniList";
"AniList Match" = "مطابقة AniList";
"AniList.co" = "AniList.co";
"Anonymous data is collected to improve the app. No personal information is collected. This can be disabled at any time." = "يتم جمع بيانات مجهولة المصدر لتحسين التطبيق. لا يتم جمع أي معلومات شخصية. يمكن تعطيل هذا في أي وقت.";
"App Info" = "معلومات التطبيق";
"App Language" = "لغة التطبيق";
"App Storage" = "تخزين التطبيق";
"Appearance" = "المظهر";
/* Alerts and Actions */
"Are you sure you want to clear all cached data? This will help free up storage space." = "هل أنت متأكد من أنك تريد مسح جميع بيانات ذاكرة التخزين المؤقت؟ سيساعد هذا في تحرير مساحة التخزين.";
"Are you sure you want to delete '%@'?" = "هل أنت متأكد أنك تريد حذف '%@'؟";
"Are you sure you want to delete all %1$d episodes in '%2$@'?" = "هل أنت متأكد أنك تريد حذف جميع الحلقات البالغ عددها %1$d في '%2$@'؟";
"Are you sure you want to delete all downloaded assets? You can choose to clear only the library while preserving the downloaded files for future use." = "هل أنت متأكد من أنك تريد حذف جميع الأصول التي تم تنزيلها؟ يمكنك اختيار مسح المكتبة فقط مع الاحتفاظ بالملفات التي تم تنزيلها للاستخدام في المستقبل.";
"Are you sure you want to erase all app data? This action cannot be undone." = "هل أنت متأكد أنك تريد محو جميع بيانات التطبيق؟ هذا الإجراء لا يمكن التراجع عنه.";
/* Features */
"Background Enabled" = "التفعيل في الخلفية";
"Bookmark items for an easier access later." = "احفظ العناصر للوصول إليها بسهولة لاحقًا.";
"Bookmarks" = "العناصر المحفوظة";
"Bottom Padding" = "الحشوة السفلية";
"Cancel" = "إلغاء";
"Cellular Quality" = "جودة بيانات الجوال";
"Check out some community modules here!" = "اطلع على بعض وحدات المجتمع هنا!";
"Choose preferred video resolution for WiFi and cellular connections. Higher resolutions use more data but provide better quality." = "اختر دقة الفيديو المفضلة لاتصالات WiFi وبيانات الجوال. الدقة الأعلى تستهلك المزيد من البيانات ولكنها توفر جودة أفضل.";
"Clear" = "مسح";
"Clear All Downloads" = "مسح كل التنزيلات";
"Clear Cache" = "مسح ذاكرة التخزين المؤقت";
"Clear Library Only" = "مسح المكتبة فقط";
"Clear Logs" = "مسح السجلات";
"Click the plus button to add a module!" = "انقر على زر الإضافة لإضافة وحدة!";
"Continue Watching" = "متابعة المشاهدة";
"Continue Watching Episode %d" = "متابعة مشاهدة الحلقة %d";
"Contributors" = "المساهمون";
"Copied to Clipboard" = "تم النسخ إلى الحافظة";
"Copy to Clipboard" = "نسخ إلى الحافظة";
"Copy URL" = "نسخ الرابط";
/* Episodes */
"%lld Episodes" = "%lld حلقات";
"%lld of %lld" = "%1$lld من %2$lld";
"%lld-%lld" = "%1$lld-%2$lld";
"%lld%% seen" = "تمت مشاهدة %lld%%";
"Episode %lld" = "الحلقة %lld";
"Episodes" = "الحلقات";
"Episodes might not be available yet or there could be an issue with the source." = "قد لا تكون الحلقات متاحة بعد أو قد تكون هناك مشكلة في المصدر.";
"Episodes Range" = "نطاق الحلقات";
/* System */
"cranci1" = "cranci1";
"Dark" = "داكن";
"DATA & LOGS" = "البيانات والسجلات";
"Debug" = "تصحيح الأخطاء";
"Debugging and troubleshooting." = "تصحيح الأخطاء وإصلاحها.";
/* Actions */
"Delete" = "حذف";
"Delete All" = "حذف الكل";
"Delete All Downloads" = "حذف كل التنزيلات";
"Delete All Episodes" = "حذف كل الحلقات";
"Delete Download" = "حذف التنزيل";
"Delete Episode" = "حذف الحلقة";
/* Player */
"Double Tap to Seek" = "انقر نقرًا مزدوجًا للتقديم";
"Double tapping the screen on it's sides will skip with the short tap setting." = "النقر المزدوج على جانبي الشاشة سيقوم بالتقديم حسب إعداد النقر القصير.";
/* Downloads */
"Download" = "تنزيل";
"Download Episode" = "تنزيل الحلقة";
"Download Summary" = "ملخص التنزيل";
"Download This Episode" = "تنزيل هذه الحلقة";
"Downloaded" = "تم التنزيل";
"Downloaded Shows" = "العروض المنزّلة";
"Downloading" = "جاري التنزيل";
"Downloads" = "التنزيلات";
/* Settings */
"Enable Analytics" = "تفعيل التحليلات";
"Enable Subtitles" = "تفعيل الترجمة";
/* Data Management */
"Erase" = "محو";
"Erase all App Data" = "محو كل بيانات التطبيق";
"Erase App Data" = "محو بيانات التطبيق";
/* Errors */
"Error" = "خطأ";
"Error Fetching Results" = "خطأ في جلب النتائج";
"Errors and critical issues." = "الأخطاء والمشاكل الحرجة.";
"Failed to load contributors" = "فشل تحميل المساهمين";
/* Features */
"Fetch Episode metadata" = "جلب بيانات الحلقة الوصفية";
"Files Downloaded" = "الملفات المنزّلة";
"Font Size" = "حجم الخط";
/* Interface */
"Force Landscape" = "فرض الوضع الأفقي";
"General" = "عام";
"General events and activities." = "الأحداث والأنشطة العامة.";
"General Preferences" = "التفضيلات العامة";
"Hide Splash Screen" = "إخفاء شاشة البداية";
"HLS video downloading." = "تنزيل فيديو HLS.";
"Hold Speed" = "سرعة الضغط المطول";
/* Info */
"Info" = "معلومات";
"INFOS" = "معلومات";
"Installed Modules" = "الوحدات المثبتة";
"Interface" = "الواجهة";
/* Social */
"Join the Discord" = "انضم إلى ديسكورد";
/* Layout */
"Landscape Columns" = "أعمدة الوضع الأفقي";
"Language" = "اللغة";
"LESS" = "أقل";
/* Library */
"Library" = "المكتبة";
"License (GPLv3.0)" = "الرخصة (GPLv3.0)";
"Light" = "فاتح";
/* Loading States */
"Loading Episode %lld..." = "جاري تحميل الحلقة %lld...";
"Loading logs..." = "جاري تحميل السجلات...";
"Loading module information..." = "جاري تحميل معلومات الوحدة...";
"Loading Stream" = "جاري تحميل البث";
/* Logging */
"Log Debug Info" = "تسجيل معلومات تصحيح الأخطاء";
"Log Filters" = "مرشحات السجل";
"Log In with AniList" = "تسجيل الدخول باستخدام AniList";
"Log In with Trakt" = "تسجيل الدخول باستخدام Trakt";
"Log Out from AniList" = "تسجيل الخروج من AniList";
"Log Out from Trakt" = "تسجيل الخروج من Trakt";
"Log Types" = "أنواع السجل";
"Logged in as" = "تم تسجيل الدخول باسم";
"Logged in as " = "تم تسجيل الدخول باسم ";
/* Logs and Settings */
"Logs" = "السجلات";
"Long press Skip" = "ضغط مطول للتخطي";
"MAIN" = "الرئيسية";
"Main Developer" = "المطور الرئيسي";
"MAIN SETTINGS" = "الإعدادات الرئيسية";
/* Media Actions */
"Mark All Previous Watched" = "تمييز كل ما سبق كمشاهد";
"Mark as Watched" = "تمييز كمشاهد";
"Mark Episode as Watched" = "تمييز الحلقة كمشاهدة";
"Mark Previous Episodes as Watched" = "تمييز الحلقات السابقة كمشاهدة";
"Mark watched" = "تمييز كمشاهد";
"Match with AniList" = "مطابقة مع AniList";
"Match with TMDB" = "مطابقة مع TMDB";
"Matched ID: %lld" = "المعرّف المطابق: %lld";
"Matched with: %@" = "تمت المطابقة مع: %@";
"Max Concurrent Downloads" = "الحد الأقصى للتنزيلات المتزامنة";
/* Media Interface */
"Media Grid Layout" = "تخطيط شبكة المحتوى";
"Media Player" = "مشغل المحتوى";
"Media View" = "عرض المحتوى";
"Metadata Provider" = "مزود البيانات الوصفية";
"Metadata Providers Order" = "ترتيب مزودي البيانات الوصفية";
"Module Removed" = "تمت إزالة الوحدة";
"Modules" = "الوحدات";
/* Headers */
"MODULES" = "الوحدات";
"MORE" = "المزيد";
/* Status Messages */
"No Active Downloads" = "لا توجد تنزيلات نشطة";
"No AniList matches found" = "لم يتم العثور على مطابقات في AniList";
"No Data Available" = "لا توجد بيانات متاحة";
"No Downloads" = "لا توجد تنزيلات";
"No episodes available" = "لا توجد حلقات متاحة";
"No Episodes Available" = "لا توجد حلقات متاحة";
"No items to continue watching." = "لا توجد عناصر لمتابعة مشاهدتها.";
"No matches found" = "لم يتم العثور على نتائج";
"No Module Selected" = "لم يتم تحديد أي وحدة";
"No Modules" = "لا توجد وحدات";
"No Results Found" = "لم يتم العثور على نتائج";
"No Search Results Found" = "لم يتم العثور على نتائج بحث";
"Nothing to Continue Watching" = "لا شيء لمتابعة مشاهدته";
/* Notes and Messages */
"Note that the modules will be replaced only if there is a different version string inside the JSON file." = "ملاحظة: سيتم استبدال الوحدات فقط في حالة وجود سلسلة إصدار مختلفة داخل ملف JSON.";
/* Actions */
"OK" = "موافق";
"Open Community Library" = "فتح مكتبة المجتمع";
/* External Services */
"Open in AniList" = "فتح في AniList";
"Original Poster" = "الملصق الأصلي";
/* Playback */
"Paused" = "متوقف مؤقتًا";
"Play" = "تشغيل";
"Player" = "المشغل";
/* System Messages */
"Please restart the app to apply the language change." = "يرجى إعادة تشغيل التطبيق لتطبيق تغيير اللغة.";
"Please select a module from settings" = "يرجى تحديد وحدة من الإعدادات";
/* Interface */
"Portrait Columns" = "أعمدة الوضع الرأسي";
"Progress bar Marker Color" = "لون علامة شريط التقدم";
"Provider: %@" = "المزود: %@";
/* Queue */
"Queue" = "قائمة الانتظار";
"Queued" = "في قائمة الانتظار";
/* Content */
"Recently watched content will appear here." = "سيظهر المحتوى الذي تمت مشاهدته مؤخرًا هنا.";
/* Settings */
"Refresh Modules on Launch" = "تحديث الوحدات عند التشغيل";
"Refresh Storage Info" = "تحديث معلومات التخزين";
"Remember Playback speed" = "تذكر سرعة التشغيل";
/* Actions */
"Remove" = "إزالة";
"Remove All Cache" = "إزالة كل ذاكرة التخزين المؤقت";
/* File Management */
"Remove All Documents" = "إزالة كل المستندات";
"Remove Documents" = "إزالة المستندات";
"Remove Downloaded Media" = "إزالة المحتوى المنزل";
"Remove Downloads" = "إزالة التنزيلات";
"Remove from Bookmarks" = "إزالة من العناصر المحفوظة";
"Remove Item" = "إزالة العنصر";
/* Support */
"Report an Issue" = "الإبلاغ عن مشكلة";
/* Reset Options */
"Reset" = "إعادة تعيين";
"Reset AniList ID" = "إعادة تعيين معرّف AniList";
"Reset Episode Progress" = "إعادة تعيين تقدم الحلقة";
"Reset progress" = "إعادة تعيين التقدم";
"Reset Progress" = "إعادة تعيين التقدم";
/* System */
"Restart Required" = "إعادة التشغيل مطلوبة";
"Running Sora %@ - cranci1" = "يعمل Sora %@ - بواسطة cranci1";
/* Actions */
"Save" = "حفظ";
"Search" = "بحث";
/* Search */
"Search downloads" = "بحث في التنزيلات";
"Search for something..." = "ابحث عن شيء ما...";
"Search..." = "بحث...";
/* Content */
"Season %d" = "الموسم %d";
"Season %lld" = "الموسم %lld";
"Segments Color" = "لون الأجزاء";
/* Modules */
"Select Module" = "تحديد وحدة";
"Set Custom AniList ID" = "تعيين معرّف AniList مخصص";
/* Interface */
"Settings" = "الإعدادات";
"Shadow" = "ظل";
"Show More (%lld more characters)" = "عرض المزيد (%lld أحرف إضافية)";
"Show PiP Button" = "إظهار زر صورة داخل صورة";
"Show Skip 85s Button" = "إظهار زر تخطي 85 ثانية";
"Show Skip Intro / Outro Buttons" = "إظهار أزرار تخطي المقدمة / الخاتمة";
"Shows" = "العروض";
"Size (%@)" = "الحجم (%@)";
"Skip Settings" = "إعدادات التخطي";
/* Player Features */
"Some features are limited to the Sora and Default player, such as ForceLandscape, holdSpeed and custom time skip increments." = "بعض الميزات تقتصر على مشغل Sora والمشغل الافتراضي، مثل فرض الوضع الأفقي، وسرعة الضغط المطول، وزيادات التخطي الزمني المخصصة.";
/* App Info */
"Sora" = "Sora";
"Sora %@ by cranci1" = "Sora %@ بواسطة cranci1";
"Sora and cranci1 are not affiliated with AniList or Trakt in any way.\n\nAlso note that progress updates may not be 100% accurate." = "Sora و cranci1 غير تابعين لـ AniList أو Trakt بأي شكل من الأشكال.\n\nيرجى ملاحظة أن تحديثات التقدم قد لا تكون دقيقة بنسبة 100%.";
"Sora GitHub Repository" = "مستودع Sora على GitHub";
"Sora/Sulfur will always remain free with no ADs!" = "سيظل Sora/Sulfur دائمًا مجانيًا وبدون إعلانات!";
/* Interface */
"Sort" = "فرز";
"Speed Settings" = "إعدادات السرعة";
/* Playback */
"Start Watching" = "ابدأ المشاهدة";
"Start Watching Episode %d" = "ابدأ مشاهدة الحلقة %d";
"Storage Used" = "المساحة المستخدمة";
"Stream" = "بث";
"Streaming and video playback." = "البث وتشغيل الفيديو.";
/* Subtitles */
"Subtitle Color" = "لون الترجمة";
"Subtitle Settings" = "إعدادات الترجمة";
/* Sync */
"Sync anime progress" = "مزامنة تقدم الأنمي";
"Sync TV shows progress" = "مزامنة تقدم المسلسلات";
/* System */
"System" = "النظام";
/* Instructions */
"Tap a title to override the current match." = "انقر على عنوان لتجاوز المطابقة الحالية.";
"Tap Skip" = "انقر للتخطي";
"Tap to manage your modules" = "انقر لإدارة وحداتك";
"Tap to select a module" = "انقر لتحديد وحدة";
/* App Information */
"The app cache helps the app load images faster.\n\nClearing the Documents folder will delete all downloaded modules.\n\nDo not erase App Data unless you understand the consequences — it may cause the app to malfunction." = "تساعد ذاكرة التخزين المؤقت للتطبيق في تحميل الصور بشكل أسرع.\n\nسيؤدي مسح مجلد المستندات إلى حذف جميع الوحدات التي تم تنزيلها.\n\nلا تقم بمحو بيانات التطبيق إلا إذا كنت تفهم العواقب — فقد يتسبب ذلك في تعطل التطبيق.";
"The episode range controls how many episodes appear on each page. Episodes are grouped into sets (like 125, 2650, and so on), allowing you to navigate through them more easily.\n\nFor episode metadata, it refers to the episode thumbnail and title, since sometimes it can contain spoilers." = "يتحكم نطاق الحلقات في عدد الحلقات التي تظهر في كل صفحة. يتم تجميع الحلقات في مجموعات (مثل 1-25، 26-50، وهكذا)، مما يتيح لك التنقل بينها بسهولة أكبر.\n\nبالنسبة لبيانات الحلقة الوصفية، فإنها تشير إلى الصورة المصغرة للحلقة وعنوانها، حيث يمكن أن تحتوي أحيانًا على حرق للأحداث.";
"The module provided only a single episode, this is most likely a movie, so we decided to make separate screens for these cases." = "قدمت الوحدة حلقة واحدة فقط، ومن المرجح أن يكون هذا فيلمًا، لذلك قررنا إنشاء شاشات منفصلة لهذه الحالات.";
/* Interface */
"Thumbnails Width" = "عرض الصور المصغرة";
"TMDB Match" = "مطابقة TMDB";
"Trackers" = "المتتبعات";
"Trakt" = "Trakt";
"Trakt.tv" = "Trakt.tv";
/* Search */
"Try different keywords" = "جرب كلمات مفتاحية مختلفة";
"Try different search terms" = "جرب مصطلحات بحث مختلفة";
/* Player Controls */
"Two Finger Hold for Pause" = "اضغط بإصبعين للإيقاف المؤقت";
"Unable to fetch matches. Please try again later." = "تعذر جلب المطابقات. يرجى المحاولة مرة أخرى لاحقًا.";
"Use TMDB Poster Image" = "استخدام صورة ملصق TMDB";
/* Version */
"v%@" = "v%@";
"Video Player" = "مشغل الفيديو";
/* Video Settings */
"Video Quality Preferences" = "تفضيلات جودة الفيديو";
"View All" = "عرض الكل";
"Watched" = "تمت مشاهدته";
"Why am I not seeing any episodes?" = "لماذا لا أرى أي حلقات؟";
"WiFi Quality" = "جودة WiFi";
/* User Status */
"You are not logged in" = "أنت غير مسجل الدخول";
"You have no items saved." = "ليس لديك عناصر محفوظة.";
"Your downloaded episodes will appear here" = "ستظهر حلقاتك المنزّلة هنا";
"Your recently watched content will appear here" = "سيظهر المحتوى الذي شاهدته مؤخرًا هنا";
/* Download Settings */
"Download Settings" = "إعدادات التنزيل";
"Max concurrent downloads controls how many episodes can download simultaneously. Higher values may use more bandwidth and device resources." = "يتحكم الحد الأقصى للتنزيلات المتزامنة في عدد الحلقات التي يمكن تنزيلها في وقت واحد. قد تستهلك القيم الأعلى المزيد من النطاق الترددي وموارد الجهاز.";
"Quality" = "الجودة";
"Max Concurrent Downloads" = "الحد الأقصى للتنزيلات المتزامنة";
"Allow Cellular Downloads" = "السماح بالتنزيلات عبر بيانات الجوال";
"Quality Information" = "معلومات الجودة";
/* Storage */
"Storage Management" = "إدارة التخزين";
"Storage Used" = "المساحة المستخدمة";
"Library cleared successfully" = "تم مسح المكتبة بنجاح";
"All downloads deleted successfully" = "تم حذف جميع التنزيلات بنجاح";

View file

@ -0,0 +1,384 @@
/* General */
"About" = "About";
"About Sora" = "About Sora";
"Active" = "Active";
"Active Downloads" = "Active Downloads";
"Actively downloading media can be tracked from here." = "Actively downloading media can be tracked from here.";
"Add Module" = "Add Module";
"Adjust the number of media items per row in portrait and landscape modes." = "Adjust the number of media items per row in portrait and landscape modes.";
"Advanced" = "Advanced";
"AKA Sulfur" = "AKA Sulfur";
"All Bookmarks" = "All Bookmarks";
"All Watching" = "All Watching";
"Also known as Sulfur" = "Also known as Sulfur";
"AniList" = "AniList";
"AniList ID" = "AniList ID";
"AniList Match" = "AniList Match";
"AniList.co" = "AniList.co";
"Anonymous data is collected to improve the app. No personal information is collected. This can be disabled at any time." = "Anonymous data is collected to improve the app. No personal information is collected. This can be disabled at any time.";
"App Info" = "App Info";
"App Language" = "App Language";
"App Storage" = "App Storage";
"Appearance" = "Appearance";
/* Alerts and Actions */
"Are you sure you want to clear all cached data? This will help free up storage space." = "Are you sure you want to clear all cached data? This will help free up storage space.";
"Are you sure you want to delete '%@'?" = "Are you sure you want to delete '%@'?";
"Are you sure you want to delete all %1$d episodes in '%2$@'?" = "Are you sure you want to delete all %1$d episodes in '%2$@'?";
"Are you sure you want to delete all downloaded assets? You can choose to clear only the library while preserving the downloaded files for future use." = "Are you sure you want to delete all downloaded assets? You can choose to clear only the library while preserving the downloaded files for future use.";
"Are you sure you want to erase all app data? This action cannot be undone." = "Are you sure you want to erase all app data? This action cannot be undone.";
/* Features */
"Background Enabled" = "Background Enabled";
"Bookmark items for an easier access later." = "Bookmark items for an easier access later.";
"Bookmarks" = "Bookmarks";
"Bottom Padding" = "Bottom Padding";
"Cancel" = "Cancel";
"Cellular Quality" = "Cellular Quality";
"Check out some community modules here!" = "Check out some community modules here!";
"Choose preferred video resolution for WiFi and cellular connections. Higher resolutions use more data but provide better quality." = "Choose preferred video resolution for WiFi and cellular connections. Higher resolutions use more data but provide better quality.";
"Clear" = "Clear";
"Clear All Downloads" = "Clear All Downloads";
"Clear Cache" = "Clear Cache";
"Clear Library Only" = "Clear Library Only";
"Clear Logs" = "Clear Logs";
"Click the plus button to add a module!" = "Click the plus button to add a module!";
"Continue Watching" = "Continue Watching";
"Continue Watching Episode %d" = "Continue Watching Episode %d";
"Contributors" = "Contributors";
"Copied to Clipboard" = "Copied to Clipboard";
"Copy to Clipboard" = "Copy to Clipboard";
"Copy URL" = "Copy URL";
/* Episodes */
"%lld Episodes" = "%lld Episodes";
"%lld of %lld" = "%1$lld of %2$lld";
"%lld-%lld" = "%1$lld-%2$lld";
"%lld%% seen" = "%lld%% seen";
"Episode %lld" = "Episode %lld";
"Episodes" = "Episodes";
"Episodes might not be available yet or there could be an issue with the source." = "Episodes might not be available yet or there could be an issue with the source.";
"Episodes Range" = "Episodes Range";
/* System */
"cranci1" = "cranci1";
"Dark" = "Dark";
"DATA & LOGS" = "DATA & LOGS";
"Debug" = "Debug";
"Debugging and troubleshooting." = "Debugging and troubleshooting.";
/* Actions */
"Delete" = "Delete";
"Delete All" = "Delete All";
"Delete All Downloads" = "Delete All Downloads";
"Delete All Episodes" = "Delete All Episodes";
"Delete Download" = "Delete Download";
"Delete Episode" = "Delete Episode";
/* Player */
"Double Tap to Seek" = "Double Tap to Seek";
"Double tapping the screen on it's sides will skip with the short tap setting." = "Double tapping the screen on it's sides will skip with the short tap setting.";
/* Downloads */
"Download" = "Download";
"Download Episode" = "Download Episode";
"Download Summary" = "Download Summary";
"Download This Episode" = "Download This Episode";
"Downloaded" = "Downloaded";
"Downloaded Shows" = "Downloaded Shows";
"Downloading" = "Downloading";
"Downloads" = "Downloads";
/* Settings */
"Enable Analytics" = "Enable Analytics";
"Enable Subtitles" = "Enable Subtitles";
/* Data Management */
"Erase" = "Erase";
"Erase all App Data" = "Erase all App Data";
"Erase App Data" = "Erase App Data";
/* Errors */
"Error" = "Error";
"Error Fetching Results" = "Error Fetching Results";
"Errors and critical issues." = "Errors and critical issues.";
"Failed to load contributors" = "Failed to load contributors";
/* Features */
"Fetch Episode metadata" = "Fetch Episode metadata";
"Files Downloaded" = "Files Downloaded";
"Font Size" = "Font Size";
/* Interface */
"Force Landscape" = "Force Landscape";
"General" = "General";
"General events and activities." = "General events and activities.";
"General Preferences" = "General Preferences";
"Hide Splash Screen" = "Hide Splash Screen";
"HLS video downloading." = "HLS video downloading.";
"Hold Speed" = "Hold Speed";
/* Info */
"Info" = "Info";
"INFOS" = "INFOS";
"Installed Modules" = "Installed Modules";
"Interface" = "Interface";
/* Social */
"Join the Discord" = "Join the Discord";
/* Layout */
"Landscape Columns" = "Landscape Columns";
"Language" = "Language";
"LESS" = "LESS";
/* Library */
"Library" = "Library";
"License (GPLv3.0)" = "License (GPLv3.0)";
"Light" = "Light";
/* Loading States */
"Loading Episode %lld..." = "Loading Episode %lld...";
"Loading logs..." = "Loading logs...";
"Loading module information..." = "Loading module information...";
"Loading Stream" = "Loading Stream";
/* Logging */
"Log Debug Info" = "Log Debug Info";
"Log Filters" = "Log Filters";
"Log In with AniList" = "Log In with AniList";
"Log In with Trakt" = "Log In with Trakt";
"Log Out from AniList" = "Log Out from AniList";
"Log Out from Trakt" = "Log Out from Trakt";
"Log Types" = "Log Types";
"Logged in as" = "Logged in as";
"Logged in as " = "Logged in as ";
/* Logs and Settings */
"Logs" = "Logs";
"Long press Skip" = "Long press Skip";
"MAIN" = "Main Settings";
"Main Developer" = "Main Developer";
"MAIN SETTINGS" = "MAIN SETTINGS";
/* Media Actions */
"Mark All Previous Watched" = "Mark All Previous Watched";
"Mark as Watched" = "Mark as Watched";
"Mark Episode as Watched" = "Mark Episode as Watched";
"Mark Previous Episodes as Watched" = "Mark Previous Episodes as Watched";
"Mark watched" = "Mark watched";
"Match with AniList" = "Match with AniList";
"Match with TMDB" = "Match with TMDB";
"Matched ID: %lld" = "Matched ID: %lld";
"Matched with: %@" = "Matched with: %@";
"Max Concurrent Downloads" = "Max Concurrent Downloads";
/* Media Interface */
"Media Grid Layout" = "Media Grid Layout";
"Media Player" = "Media Player";
"Media View" = "Media View";
"Metadata Provider" = "Metadata Provider";
"Metadata Providers Order" = "Metadata Providers Order";
"Module Removed" = "Module Removed";
"Modules" = "Modules";
/* Headers */
"MODULES" = "MODULES";
"MORE" = "MORE";
/* Status Messages */
"No Active Downloads" = "No Active Downloads";
"No AniList matches found" = "No AniList matches found";
"No Data Available" = "No Data Available";
"No Downloads" = "No Downloads";
"No episodes available" = "No episodes available";
"No Episodes Available" = "No Episodes Available";
"No items to continue watching." = "No items to continue watching.";
"No matches found" = "No matches found";
"No Module Selected" = "No Module Selected";
"No Modules" = "No Modules";
"No Results Found" = "No Results Found";
"No Search Results Found" = "No Search Results Found";
"Nothing to Continue Watching" = "Nothing to Continue Watching";
/* Notes and Messages */
"Note that the modules will be replaced only if there is a different version string inside the JSON file." = "Note that the modules will be replaced only if there is a different version string inside the JSON file.";
/* Actions */
"OK" = "OK";
"Open Community Library" = "Open Community Library";
/* External Services */
"Open in AniList" = "Open in AniList";
"Original Poster" = "Original Poster";
/* Playback */
"Paused" = "Paused";
"Play" = "Play";
"Player" = "Player";
/* System Messages */
"Please restart the app to apply the language change." = "Please restart the app to apply the language change.";
"Please select a module from settings" = "Please select a module from settings";
/* Interface */
"Portrait Columns" = "Portrait Columns";
"Progress bar Marker Color" = "Progress bar Marker Color";
"Provider: %@" = "Provider: %@";
/* Queue */
"Queue" = "Queue";
"Queued" = "Queued";
/* Content */
"Recently watched content will appear here." = "Recently watched content will appear here.";
/* Settings */
"Refresh Modules on Launch" = "Refresh Modules on Launch";
"Refresh Storage Info" = "Refresh Storage Info";
"Remember Playback speed" = "Remember Playback speed";
/* Actions */
"Remove" = "Remove";
"Remove All Cache" = "Remove All Cache";
/* File Management */
"Remove All Documents" = "Remove All Documents";
"Remove Documents" = "Remove Documents";
"Remove Downloaded Media" = "Remove Downloaded Media";
"Remove Downloads" = "Remove Downloads";
"Remove from Bookmarks" = "Remove from Bookmarks";
"Remove Item" = "Remove Item";
/* Support */
"Report an Issue" = "Report an Issue";
/* Reset Options */
"Reset" = "Reset";
"Reset AniList ID" = "Reset AniList ID";
"Reset Episode Progress" = "Reset Episode Progress";
"Reset progress" = "Reset progress";
"Reset Progress" = "Reset Progress";
/* System */
"Restart Required" = "Restart Required";
"Running Sora %@ - cranci1" = "Running Sora %@ - cranci1";
/* Actions */
"Save" = "Save";
"Search" = "Search";
/* Search */
"Search downloads" = "Search downloads";
"Search for something..." = "Search for something...";
"Search..." = "Search...";
/* Content */
"Season %d" = "Season %d";
"Season %lld" = "Season %lld";
"Segments Color" = "Segments Color";
/* Modules */
"Select Module" = "Select Module";
"Set Custom AniList ID" = "Set Custom AniList ID";
/* Interface */
"Settings" = "Settings";
"Shadow" = "Shadow";
"Show More (%lld more characters)" = "Show More (%lld more characters)";
"Show PiP Button" = "Show PiP Button";
"Show Skip 85s Button" = "Show Skip 85s Button";
"Show Skip Intro / Outro Buttons" = "Show Skip Intro / Outro Buttons";
"Shows" = "Shows";
"Size (%@)" = "Size (%@)";
"Skip Settings" = "Skip Settings";
/* Player Features */
"Some features are limited to the Sora and Default player, such as ForceLandscape, holdSpeed and custom time skip increments." = "Some features are limited to the Sora and Default player, such as ForceLandscape, holdSpeed and custom time skip increments.";
/* App Info */
"Sora" = "Sora";
"Sora %@ by cranci1" = "Sora %@ by cranci1";
"Sora and cranci1 are not affiliated with AniList or Trakt in any way.\n\nAlso note that progress updates may not be 100% accurate." = "Sora and cranci1 are not affiliated with AniList or Trakt in any way.\n\nAlso note that progress updates may not be 100% accurate.";
"Sora GitHub Repository" = "Sora GitHub Repository";
"Sora/Sulfur will always remain free with no ADs!" = "Sora/Sulfur will always remain free with no ADs!";
/* Interface */
"Sort" = "Sort";
"Speed Settings" = "Speed Settings";
/* Playback */
"Start Watching" = "Start Watching";
"Start Watching Episode %d" = "Start Watching Episode %d";
"Storage Used" = "Storage Used";
"Stream" = "Stream";
"Streaming and video playback." = "Streaming and video playback.";
/* Subtitles */
"Subtitle Color" = "Subtitle Color";
"Subtitle Settings" = "Subtitle Settings";
/* Sync */
"Sync anime progress" = "Sync anime progress";
"Sync TV shows progress" = "Sync TV shows progress";
/* System */
"System" = "System";
/* Instructions */
"Tap a title to override the current match." = "Tap a title to override the current match.";
"Tap Skip" = "Tap Skip";
"Tap to manage your modules" = "Tap to manage your modules";
"Tap to select a module" = "Tap to select a module";
/* App Information */
"The app cache helps the app load images faster.\n\nClearing the Documents folder will delete all downloaded modules.\n\nDo not erase App Data unless you understand the consequences — it may cause the app to malfunction." = "The app cache helps the app load images faster.\n\nClearing the Documents folder will delete all downloaded modules.\n\nDo not erase App Data unless you understand the consequences — it may cause the app to malfunction.";
"The episode range controls how many episodes appear on each page. Episodes are grouped into sets (like 125, 2650, and so on), allowing you to navigate through them more easily.\n\nFor episode metadata, it refers to the episode thumbnail and title, since sometimes it can contain spoilers." = "The episode range controls how many episodes appear on each page. Episodes are grouped into sets (like 125, 2650, and so on), allowing you to navigate through them more easily.\n\nFor episode metadata, it refers to the episode thumbnail and title, since sometimes it can contain spoilers.";
"The module provided only a single episode, this is most likely a movie, so we decided to make separate screens for these cases." = "The module provided only a single episode, this is most likely a movie, so we decided to make separate screens for these cases.";
/* Interface */
"Thumbnails Width" = "Thumbnails Width";
"TMDB Match" = "TMDB Match";
"Trackers" = "Trackers";
"Trakt" = "Trakt";
"Trakt.tv" = "Trakt.tv";
/* Search */
"Try different keywords" = "Try different keywords";
"Try different search terms" = "Try different search terms";
/* Player Controls */
"Two Finger Hold for Pause" = "Two Finger Hold for Pause";
"Unable to fetch matches. Please try again later." = "Unable to fetch matches. Please try again later.";
"Use TMDB Poster Image" = "Use TMDB Poster Image";
/* Version */
"v%@" = "v%@";
"Video Player" = "Video Player";
/* Video Settings */
"Video Quality Preferences" = "Video Quality Preferences";
"View All" = "View All";
"Watched" = "Watched";
"Why am I not seeing any episodes?" = "Why am I not seeing any episodes?";
"WiFi Quality" = "WiFi Quality";
/* User Status */
"You are not logged in" = "You are not logged in";
"You have no items saved." = "You have no items saved.";
"Your downloaded episodes will appear here" = "Your downloaded episodes will appear here";
"Your recently watched content will appear here" = "Your recently watched content will appear here";
/* Download Settings */
"Download Settings" = "Download Settings";
"Max concurrent downloads controls how many episodes can download simultaneously. Higher values may use more bandwidth and device resources." = "Max concurrent downloads controls how many episodes can download simultaneously. Higher values may use more bandwidth and device resources.";
"Quality" = "Quality";
"Max Concurrent Downloads" = "Max Concurrent Downloads";
"Allow Cellular Downloads" = "Allow Cellular Downloads";
"Quality Information" = "Quality Information";
/* Storage */
"Storage Management" = "Storage Management";
"Storage Used" = "Storage Used";
"Library cleared successfully" = "Library cleared successfully";
"All downloads deleted successfully" = "All downloads deleted successfully";

View file

@ -0,0 +1,384 @@
/* General */
"About" = "À propos";
"About Sora" = "À propos de Sora";
"Active" = "Actif";
"Active Downloads" = "Téléchargements actifs";
"Actively downloading media can be tracked from here." = "Les médias en cours de téléchargement peuvent être suivis ici.";
"Add Module" = "Ajouter un module";
"Adjust the number of media items per row in portrait and landscape modes." = "Ajustez le nombre d'éléments multimédias par ligne en mode portrait et paysage.";
"Advanced" = "Avancé";
"AKA Sulfur" = "Aussi connu sous le nom de Sulfur";
"All Bookmarks" = "Tous les favoris";
"All Watching" = "Tout ce que je regarde";
"Also known as Sulfur" = "Aussi connu sous le nom de Sulfur";
"AniList" = "AniList";
"AniList ID" = "ID AniList";
"AniList Match" = "Correspondance AniList";
"AniList.co" = "AniList.co";
"Anonymous data is collected to improve the app. No personal information is collected. This can be disabled at any time." = "Des données anonymes sont collectées pour améliorer l'application. Aucune information personnelle n'est collectée. Ceci peut être désactivé à tout moment.";
"App Info" = "Infos sur l'application";
"App Language" = "Langue de l'application";
"App Storage" = "Stockage de l'application";
"Appearance" = "Apparence";
/* Alerts and Actions */
"Are you sure you want to clear all cached data? This will help free up storage space." = "Voulez-vous vraiment vider toutes les données en cache ? Cela aidera à libérer de l'espace de stockage.";
"Are you sure you want to delete '%@'?" = "Voulez-vous vraiment supprimer '%@' ?";
"Are you sure you want to delete all %1$d episodes in '%2$@'?" = "Voulez-vous vraiment supprimer les %1$d épisodes de '%2$@' ?";
"Are you sure you want to delete all downloaded assets? You can choose to clear only the library while preserving the downloaded files for future use." = "Voulez-vous vraiment supprimer tous les fichiers téléchargés ? Vous pouvez choisir de vider uniquement la bibliothèque tout en conservant les fichiers téléchargés pour une utilisation future.";
"Are you sure you want to erase all app data? This action cannot be undone." = "Voulez-vous vraiment effacer toutes les données de l'application ? Cette action est irréversible.";
/* Features */
"Background Enabled" = "Activé en arrière-plan";
"Bookmark items for an easier access later." = "Mettez des éléments en favoris pour un accès plus facile plus tard.";
"Bookmarks" = "Favoris";
"Bottom Padding" = "Marge intérieure inférieure";
"Cancel" = "Annuler";
"Cellular Quality" = "Qualité cellulaire";
"Check out some community modules here!" = "Découvrez quelques modules communautaires ici !";
"Choose preferred video resolution for WiFi and cellular connections. Higher resolutions use more data but provide better quality." = "Choisissez la résolution vidéo préférée pour les connexions WiFi et cellulaires. Les résolutions plus élevées utilisent plus de données mais offrent une meilleure qualité.";
"Clear" = "Vider";
"Clear All Downloads" = "Vider tous les téléchargements";
"Clear Cache" = "Vider le cache";
"Clear Library Only" = "Vider la bibliothèque uniquement";
"Clear Logs" = "Vider les journaux";
"Click the plus button to add a module!" = "Cliquez sur le bouton plus pour ajouter un module !";
"Continue Watching" = "Reprendre la lecture";
"Continue Watching Episode %d" = "Reprendre l'épisode %d";
"Contributors" = "Contributeurs";
"Copied to Clipboard" = "Copié dans le presse-papiers";
"Copy to Clipboard" = "Copier dans le presse-papiers";
"Copy URL" = "Copier l'URL";
/* Episodes */
"%lld Episodes" = "%lld épisodes";
"%lld of %lld" = "%1$lld sur %2$lld";
"%lld-%lld" = "%1$lld-%2$lld";
"%lld%% seen" = "%lld%% vus";
"Episode %lld" = "Épisode %lld";
"Episodes" = "Épisodes";
"Episodes might not be available yet or there could be an issue with the source." = "Les épisodes ne sont peut-être pas encore disponibles ou il y a un problème avec la source.";
"Episodes Range" = "Plage d'épisodes";
/* System */
"cranci1" = "cranci1";
"Dark" = "Sombre";
"DATA & LOGS" = "DONNÉES & JOURNEAUX";
"Debug" = "Débogage";
"Debugging and troubleshooting." = "Débogage et résolution de problèmes.";
/* Actions */
"Delete" = "Supprimer";
"Delete All" = "Tout supprimer";
"Delete All Downloads" = "Supprimer tous les téléchargements";
"Delete All Episodes" = "Supprimer tous les épisodes";
"Delete Download" = "Supprimer le téléchargement";
"Delete Episode" = "Supprimer l'épisode";
/* Player */
"Double Tap to Seek" = "Touchez deux fois pour avancer";
"Double tapping the screen on it's sides will skip with the short tap setting." = "Appuyer deux fois sur les côtés de l'écran permet de sauter avec le réglage de pression courte.";
/* Downloads */
"Download" = "Télécharger";
"Download Episode" = "Télécharger l'épisode";
"Download Summary" = "Résumé du téléchargement";
"Download This Episode" = "Télécharger cet épisode";
"Downloaded" = "Téléchargé";
"Downloaded Shows" = "Séries téléchargées";
"Downloading" = "Téléchargement en cours";
"Downloads" = "Téléchargements";
/* Settings */
"Enable Analytics" = "Activer les analyses";
"Enable Subtitles" = "Activer les sous-titres";
/* Data Management */
"Erase" = "Effacer";
"Erase all App Data" = "Effacer toutes les données de l'app";
"Erase App Data" = "Effacer les données de l'app";
/* Errors */
"Error" = "Erreur";
"Error Fetching Results" = "Erreur lors de la récupération des résultats";
"Errors and critical issues." = "Erreurs et problèmes critiques.";
"Failed to load contributors" = "Échec du chargement des contributeurs";
/* Features */
"Fetch Episode metadata" = "Récupérer les métadonnées de l'épisode";
"Files Downloaded" = "Fichiers téléchargés";
"Font Size" = "Taille de la police";
/* Interface */
"Force Landscape" = "Forcer le mode paysage";
"General" = "Général";
"General events and activities." = "Événements et activités générales.";
"General Preferences" = "Préférences générales";
"Hide Splash Screen" = "Masquer l'écran de démarrage";
"HLS video downloading." = "Téléchargement de vidéos HLS.";
"Hold Speed" = "Vitesse de maintien";
/* Info */
"Info" = "Infos";
"INFOS" = "INFOS";
"Installed Modules" = "Modules installés";
"Interface" = "Interface";
/* Social */
"Join the Discord" = "Rejoindre le Discord";
/* Layout */
"Landscape Columns" = "Colonnes en paysage";
"Language" = "Langue";
"LESS" = "MOINS";
/* Library */
"Library" = "Bibliothèque";
"License (GPLv3.0)" = "Licence (GPLv3.0)";
"Light" = "Clair";
/* Loading States */
"Loading Episode %lld..." = "Chargement de l'épisode %lld...";
"Loading logs..." = "Chargement des journaux...";
"Loading module information..." = "Chargement des informations du module...";
"Loading Stream" = "Chargement du flux";
/* Logging */
"Log Debug Info" = "Journaliser les infos de débogage";
"Log Filters" = "Filtres de journal";
"Log In with AniList" = "Se connecter avec AniList";
"Log In with Trakt" = "Se connecter avec Trakt";
"Log Out from AniList" = "Se déconnecter d'AniList";
"Log Out from Trakt" = "Se déconnecter de Trakt";
"Log Types" = "Types de journaux";
"Logged in as" = "Connecté en tant que";
"Logged in as " = "Connecté en tant que ";
/* Logs and Settings */
"Logs" = "Journaux";
"Long press Skip" = "Pression longue pour sauter";
"MAIN" = "PRINCIPAL";
"Main Developer" = "Développeur principal";
"MAIN SETTINGS" = "RÉGLAGES PRINCIPAUX";
/* Media Actions */
"Mark All Previous Watched" = "Marquer tout comme vu";
"Mark as Watched" = "Marquer comme vu";
"Mark Episode as Watched" = "Marquer l'épisode comme vu";
"Mark Previous Episodes as Watched" = "Marquer les épisodes précédents comme vus";
"Mark watched" = "Marquer comme vu";
"Match with AniList" = "Associer avec AniList";
"Match with TMDB" = "Associer avec TMDB";
"Matched ID: %lld" = "ID associé : %lld";
"Matched with: %@" = "Associé avec : %@";
"Max Concurrent Downloads" = "Téléchargements simultanés max";
/* Media Interface */
"Media Grid Layout" = "Mise en page de la grille média";
"Media Player" = "Lecteur multimédia";
"Media View" = "Vue multimédia";
"Metadata Provider" = "Fournisseur de métadonnées";
"Metadata Providers Order" = "Ordre des fournisseurs de métadonnées";
"Module Removed" = "Module supprimé";
"Modules" = "Modules";
/* Headers */
"MODULES" = "MODULES";
"MORE" = "PLUS";
/* Status Messages */
"No Active Downloads" = "Aucun téléchargement actif";
"No AniList matches found" = "Aucune correspondance AniList trouvée";
"No Data Available" = "Aucune donnée disponible";
"No Downloads" = "Aucun téléchargement";
"No episodes available" = "Aucun épisode disponible";
"No Episodes Available" = "Aucun épisode disponible";
"No items to continue watching." = "Aucun élément à reprendre.";
"No matches found" = "Aucune correspondance trouvée";
"No Module Selected" = "Aucun module sélectionné";
"No Modules" = "Aucun module";
"No Results Found" = "Aucun résultat trouvé";
"No Search Results Found" = "Aucun résultat de recherche trouvé";
"Nothing to Continue Watching" = "Rien à reprendre";
/* Notes and Messages */
"Note that the modules will be replaced only if there is a different version string inside the JSON file." = "Notez que les modules ne seront remplacés que s'il existe une chaîne de version différente dans le fichier JSON.";
/* Actions */
"OK" = "OK";
"Open Community Library" = "Ouvrir la bibliothèque communautaire";
/* External Services */
"Open in AniList" = "Ouvrir dans AniList";
"Original Poster" = "Affiche originale";
/* Playback */
"Paused" = "En pause";
"Play" = "Lecture";
"Player" = "Lecteur";
/* System Messages */
"Please restart the app to apply the language change." = "Veuillez redémarrer l'application pour appliquer le changement de langue.";
"Please select a module from settings" = "Veuillez sélectionner un module dans les paramètres";
/* Interface */
"Portrait Columns" = "Colonnes en portrait";
"Progress bar Marker Color" = "Couleur du marqueur de la barre de progression";
"Provider: %@" = "Fournisseur : %@";
/* Queue */
"Queue" = "File d'attente";
"Queued" = "En attente";
/* Content */
"Recently watched content will appear here." = "Le contenu récemment visionné apparaîtra ici.";
/* Settings */
"Refresh Modules on Launch" = "Actualiser les modules au lancement";
"Refresh Storage Info" = "Actualiser les infos de stockage";
"Remember Playback speed" = "Mémoriser la vitesse de lecture";
/* Actions */
"Remove" = "Supprimer";
"Remove All Cache" = "Supprimer tout le cache";
/* File Management */
"Remove All Documents" = "Supprimer tous les documents";
"Remove Documents" = "Supprimer les documents";
"Remove Downloaded Media" = "Supprimer les médias téléchargés";
"Remove Downloads" = "Supprimer les téléchargements";
"Remove from Bookmarks" = "Supprimer des favoris";
"Remove Item" = "Supprimer l'élément";
/* Support */
"Report an Issue" = "Signaler un problème";
/* Reset Options */
"Reset" = "Réinitialiser";
"Reset AniList ID" = "Réinitialiser l'ID AniList";
"Reset Episode Progress" = "Réinitialiser la progression de l'épisode";
"Reset progress" = "Réinitialiser la progression";
"Reset Progress" = "Réinitialiser la progression";
/* System */
"Restart Required" = "Redémarrage requis";
"Running Sora %@ - cranci1" = "Sora %@ en cours d'exécution - cranci1";
/* Actions */
"Save" = "Enregistrer";
"Search" = "Rechercher";
/* Search */
"Search downloads" = "Rechercher dans les téléchargements";
"Search for something..." = "Rechercher quelque chose...";
"Search..." = "Rechercher...";
/* Content */
"Season %d" = "Saison %d";
"Season %lld" = "Saison %lld";
"Segments Color" = "Couleur des segments";
/* Modules */
"Select Module" = "Sélectionner un module";
"Set Custom AniList ID" = "Définir un ID AniList personnalisé";
/* Interface */
"Settings" = "Paramètres";
"Shadow" = "Ombre";
"Show More (%lld more characters)" = "Afficher plus (%lld caractères de plus)";
"Show PiP Button" = "Afficher le bouton PiP";
"Show Skip 85s Button" = "Afficher le bouton Sauter 85s";
"Show Skip Intro / Outro Buttons" = "Afficher les boutons Sauter l'intro / l'outro";
"Shows" = "Séries";
"Size (%@)" = "Taille (%@)";
"Skip Settings" = "Réglages de saut";
/* Player Features */
"Some features are limited to the Sora and Default player, such as ForceLandscape, holdSpeed and custom time skip increments." = "Certaines fonctionnalités sont limitées au lecteur Sora et par défaut, telles que Forcer Paysage, Vitesse par pression longue et les incréments de saut de temps personnalisés.";
/* App Info */
"Sora" = "Sora";
"Sora %@ by cranci1" = "Sora %@ par cranci1";
"Sora and cranci1 are not affiliated with AniList or Trakt in any way.\n\nAlso note that progress updates may not be 100% accurate." = "Sora et cranci1 ne sont en aucun cas affiliés à AniList ou Trakt.\n\nNotez également que les mises à jour de progression peuvent ne pas être précises à 100%.";
"Sora GitHub Repository" = "Dépôt GitHub de Sora";
"Sora/Sulfur will always remain free with no ADs!" = "Sora/Sulfur restera toujours gratuit et sans publicités !";
/* Interface */
"Sort" = "Trier";
"Speed Settings" = "Réglages de vitesse";
/* Playback */
"Start Watching" = "Commencer à regarder";
"Start Watching Episode %d" = "Commencer l'épisode %d";
"Storage Used" = "Stockage utilisé";
"Stream" = "Flux";
"Streaming and video playback." = "Streaming et lecture vidéo.";
/* Subtitles */
"Subtitle Color" = "Couleur des sous-titres";
"Subtitle Settings" = "Réglages des sous-titres";
/* Sync */
"Sync anime progress" = "Synchroniser la progression des animes";
"Sync TV shows progress" = "Synchroniser la progression des séries TV";
/* System */
"System" = "Système";
/* Instructions */
"Tap a title to override the current match." = "Appuyez sur un titre pour remplacer la correspondance actuelle.";
"Tap Skip" = "Appuyer pour sauter";
"Tap to manage your modules" = "Appuyez pour gérer vos modules";
"Tap to select a module" = "Appuyez pour sélectionner un module";
/* App Information */
"The app cache helps the app load images faster.\n\nClearing the Documents folder will delete all downloaded modules.\n\nDo not erase App Data unless you understand the consequences — it may cause the app to malfunction." = "Le cache de l'application permet de charger les images plus rapidement.\n\nLa suppression du dossier Documents effacera tous les modules téléchargés.\n\nN'effacez pas les données de l'application à moins de comprendre les conséquences — cela pourrait entraîner un dysfonctionnement de l'application.";
"The episode range controls how many episodes appear on each page. Episodes are grouped into sets (like 125, 2650, and so on), allowing you to navigate through them more easily.\n\nFor episode metadata, it refers to the episode thumbnail and title, since sometimes it can contain spoilers." = "La plage d'épisodes contrôle le nombre d'épisodes qui apparaissent sur chaque page. Les épisodes sont regroupés en séries (comme 125, 2650, etc.), ce qui vous permet de naviguer plus facilement.\n\nPour les métadonnées d'épisode, cela fait référence à la miniature et au titre de l'épisode, car ils peuvent parfois contenir des spoilers.";
"The module provided only a single episode, this is most likely a movie, so we decided to make separate screens for these cases." = "Le module n'a fourni qu'un seul épisode, il s'agit très probablement d'un film, nous avons donc décidé de créer des écrans séparés pour ces cas.";
/* Interface */
"Thumbnails Width" = "Largeur des miniatures";
"TMDB Match" = "Correspondance TMDB";
"Trackers" = "Trackers";
"Trakt" = "Trakt";
"Trakt.tv" = "Trakt.tv";
/* Search */
"Try different keywords" = "Essayez différents mots-clés";
"Try different search terms" = "Essayez différents termes de recherche";
/* Player Controls */
"Two Finger Hold for Pause" = "Maintenir avec deux doigts pour mettre en pause";
"Unable to fetch matches. Please try again later." = "Impossible de récupérer les correspondances. Veuillez réessayer plus tard.";
"Use TMDB Poster Image" = "Utiliser l'image de l'affiche TMDB";
/* Version */
"v%@" = "v%@";
"Video Player" = "Lecteur vidéo";
/* Video Settings */
"Video Quality Preferences" = "Préférences de qualité vidéo";
"View All" = "Voir tout";
"Watched" = "Vu";
"Why am I not seeing any episodes?" = "Pourquoi ne vois-je aucun épisode ?";
"WiFi Quality" = "Qualité WiFi";
/* User Status */
"You are not logged in" = "Vous n'êtes pas connecté";
"You have no items saved." = "Vous n'avez aucun élément enregistré.";
"Your downloaded episodes will appear here" = "Vos épisodes téléchargés apparaîtront ici";
"Your recently watched content will appear here" = "Votre contenu récemment visionné apparaîtra ici";
/* Download Settings */
"Download Settings" = "Paramètres de téléchargement";
"Max concurrent downloads controls how many episodes can download simultaneously. Higher values may use more bandwidth and device resources." = "Le nombre maximum de téléchargements simultanés contrôle le nombre d'épisodes pouvant être téléchargés en même temps. Des valeurs plus élevées peuvent utiliser plus de bande passante et de ressources de l'appareil.";
"Quality" = "Qualité";
"Max Concurrent Downloads" = "Téléchargements simultanés max";
"Allow Cellular Downloads" = "Autoriser les téléchargements cellulaires";
"Quality Information" = "Informations sur la qualité";
/* Storage */
"Storage Management" = "Gestion du stockage";
"Storage Used" = "Stockage utilisé";
"Library cleared successfully" = "Bibliothèque vidée avec succès";
"All downloads deleted successfully" = "Tous les téléchargements ont été supprimés avec succès";

View file

@ -0,0 +1,384 @@
/* General */
"About" = "Over";
"About Sora" = "Over Sora";
"Active" = "Actief";
"Active Downloads" = "Actieve Downloads";
"Actively downloading media can be tracked from here." = "Actief downloaden van media kan hier worden gevolgd.";
"Add Module" = "Module Toevoegen";
"Adjust the number of media items per row in portrait and landscape modes." = "Pas het aantal media-items per rij aan in staande en liggende modus.";
"Advanced" = "Geavanceerd";
"AKA Sulfur" = "AKA Sulfur";
"All Bookmarks" = "Alle Bladwijzers";
"All Prev" = "Alle vorige";
"All Watching" = "Alles Wat Ik Kijk";
"AniList" = "AniList";
"Anonymous data is collected to improve the app. No personal information is collected. This can be disabled at any time." = "Anonieme gegevens worden verzameld om de app te verbeteren. Er worden geen persoonlijke gegevens verzameld. Dit kan op elk moment worden uitgeschakeld.";
"App Info" = "App Info";
"App Language" = "App Taal";
"App Storage" = "App Opslag";
"Appearance" = "Uiterlijk";
/* Alerts and Actions */
"Are you sure you want to clear all cached data? This will help free up storage space." = "Weet je zeker dat je alle gecachte gegevens wilt wissen? Dit helpt opslagruimte vrij te maken.";
"Are you sure you want to delete '%@'?" = "Weet je zeker dat je '%@' wilt verwijderen?";
"Are you sure you want to delete all %1$lld episodes in '%2$@'?" = "Weet je zeker dat je alle %1$lld afleveringen in '%2$@' wilt verwijderen?";
"Are you sure you want to delete all downloaded assets? You can choose to clear only the library while preserving the downloaded files for future use." = "Weet je zeker dat je alle gedownloade bestanden wilt verwijderen? Je kunt ervoor kiezen om alleen de bibliotheek te wissen terwijl je de gedownloade bestanden voor later gebruik bewaart.";
"Are you sure you want to erase all app data? This action cannot be undone." = "Weet je zeker dat je alle app-gegevens wilt wissen? Deze actie kan niet ongedaan worden gemaakt.";
"Are you sure you want to remove all downloaded media files (.mov, .mp4, .pkg)?" = "Weet je zeker dat je alle gedownloade mediabestanden (.mov, .mp4, .pkg) wilt verwijderen?";
"Are you sure you want to remove all files in the Documents folder?" = "Weet je zeker dat je alle bestanden in de map Documenten wilt verwijderen?";
/* Features */
"Author" = "Auteur";
"Background Enabled" = "Achtergrond Ingeschakeld";
"Bookmark items for an easier access later." = "Bladwijzer items voor eenvoudigere toegang later.";
"Bookmarks" = "Bladwijzers";
"Bottom Padding" = "Onderste Padding";
"Cancel" = "Annuleren";
"Cellular Quality" = "Mobiele Kwaliteit";
"Check out some community modules here!" = "Bekijk hier enkele community modules!";
"Choose preferred video resolution for WiFi and cellular connections." = "Kies de gewenste videoresolutie voor WiFi en mobiele verbindingen.";
"Clear" = "Wissen";
"Clear All Downloads" = "Alle Downloads Wissen";
"Clear Cache" = "Wis Cache";
"Clear Library Only" = "Alleen Bibliotheek Wissen";
"Clear Logs" = "Wis Logs";
"Click the plus button to add a module!" = "Klik op de plus-knop om een module toe te voegen!";
"Continue Watching" = "Verder Kijken";
"Continue Watching Episode %d" = "Verder Kijken Aflevering %d";
"Contributors" = "Bijdragers";
"Copied to Clipboard" = "Gekopieerd naar Klembord";
"Copy to Clipboard" = "Kopiëren naar Klembord";
"Copy URL" = "Kopieer URL";
/* Episodes */
"%lld Episodes" = "%lld Afleveringen";
"%lld of %lld" = "%1$lld van %2$lld";
"%lld-%lld" = "%1$lld-%2$lld";
"%lld%% seen" = "%lld%% gezien";
"Episode %lld" = "Aflevering %lld";
"Episodes" = "Afleveringen";
"Episodes might not be available yet or there could be an issue with the source." = "Afleveringen zijn mogelijk nog niet beschikbaar of er is een probleem met de bron.";
"Episodes Range" = "Afleveringen Bereik";
/* System */
"cranci1" = "cranci1";
"Dark" = "Donker";
"DATA & LOGS" = "DATA & LOGS";
"Debug" = "Debug";
"Debugging and troubleshooting." = "Debuggen en probleemoplossing.";
/* Actions */
"Delete" = "Verwijderen";
"Delete All" = "Alles Wissen";
"Delete All Downloads" = "Alle Downloads Verwijderen";
"Delete All Episodes" = "Alle Afleveringen Wissen";
"Delete Download" = "Downloads Wissen";
"Delete Episode" = "Afleveringen Wissen";
/* Player */
"Double Tap to Seek" = "Dubbel Tikken om te Zoeken";
"Double tapping the screen on it's sides will skip with the short tap setting." = "Dubbel tikken op de zijkanten van het scherm zal overslaan met de korte tik instelling.";
/* Downloads */
"Download" = "Downloaden";
"Download Episode" = "Aflevering Downloaden";
"Download Summary" = "Download Samenvatting";
"Download This Episode" = "Download Deze Aflevering";
"Downloaded" = "Gedownload";
"Downloaded Shows" = "Gedownloade Series";
"Downloading" = "Downloaden";
"Downloads" = "Downloads";
/* Settings */
"Enable Analytics" = "Analytics Inschakelen";
"Enable Subtitles" = "Ondertiteling Inschakelen";
/* Data Management */
"Erase" = "Verwijden";
"Erase all App Data" = "Wis Alle App Data";
"Erase App Data" = "Verwijder App Data";
/* Errors */
"Error" = "Fout";
"Error Fetching Results" = "Fout bij Ophalen Resultaten";
"Errors and critical issues." = "Fouten en kritieke problemen.";
"Failed to load contributors" = "Laden van bijdragers mislukt";
/* Features */
"Fetch Episode metadata" = "Haal Aflevering Metadata op";
"Files Downloaded" = "Gedownloade Bestanden";
"Font Size" = "Lettergrootte";
/* Interface */
"Force Landscape" = "Forceer Landschap";
"General" = "Algemeen";
"General events and activities." = "Algemene gebeurtenissen en activiteiten.";
"General Preferences" = "Algemene Voorkeuren";
"Hide Splash Screen" = "Splash Screen Verbergen";
"HLS video downloading." = "HLS video downloaden.";
"Hold Speed" = "Vasthouden Snelheid";
/* Info */
"Info" = "Info";
"INFOS" = "INFO";
"Installed Modules" = "Geïnstalleerde Modules";
"Interface" = "Interface";
/* Social */
"Join the Discord" = "Word lid van de Discord";
/* Layout */
"Landscape Columns" = "Liggende Kolommen";
"Language" = "Taal";
"LESS" = "MINDER";
/* Library */
"Library" = "Bibliotheek";
"License (GPLv3.0)" = "Licentie (GPLv3.0)";
"Light" = "Licht";
/* Loading States */
"Loading Episode %lld..." = "Aflevering %lld laden...";
"Loading logs..." = "Logboeken laden...";
"Loading module information..." = "Module-informatie laden...";
"Loading Stream" = "Stream Laden";
/* Logging */
"Log Debug Info" = "Debug Info Loggen";
"Log Filters" = "Log Filters";
"Log In with AniList" = "Inloggen met AniList";
"Log In with Trakt" = "Inloggen met Trakt";
"Log Out from AniList" = "Uitloggen van AniList";
"Log Out from Trakt" = "Uitloggen van Trakt";
"Log Types" = "Logboek Types";
"Logged in as" = "Ingelogd als";
"Logged in as " = "Ingelogd als ";
/* Logs and Settings */
"Logs" = "Logboeken";
"Long press Skip" = "Lang Drukken Overslaan";
"MAIN" = "Hoofdinstellingen";
"Main Developer" = "Hoofdontwikkelaar";
"MAIN SETTINGS" = "HOOFDINSTELLINGEN";
/* Media Actions */
"Mark All Previous Watched" = "Markeer alles als gezien";
"Mark as Watched" = "Markeer als gezien";
"Mark Episode as Watched" = "Markeer aflevering als gezien";
"Mark Previous Episodes as Watched" = "Markeer vorige afleveringen als gezien";
"Mark watched" = "Markeer als gezien";
"Match with AniList" = "Match met AniList";
"Match with TMDB" = "Match met TMDB";
"Matched ID: %lld" = "Gematchte ID: %lld";
"Matched with: %@" = "Match met: %@";
"Max Concurrent Downloads" = "Maximaal gelijktijdige downloads";
/* Media Interface */
"Media Grid Layout" = "Media Raster Layout";
"Media Player" = "Media Speler";
"Media View" = "Mediaweergave";
"Metadata Provider" = "Metadata Provider";
"Metadata Providers Order" = "Metadata Providers Volgorde";
"Module Removed" = "Module Verwijderd";
"Modules" = "Modules";
/* Headers */
"MODULES" = "MODULES";
"MORE" = "MEER";
/* Status Messages */
"No Active Downloads" = "Geen Actieve Downloads";
"No AniList matches found" = "Geen AniList overeenkomsten gevonden";
"No Data Available" = "Geen Gegevens Beschikbaar";
"No Downloads" = "Geen Downloads";
"No episodes available" = "Geen afleveringen beschikbaar";
"No Episodes Available" = "Geen Afleveringen Beschikbaar";
"No items to continue watching." = "Geen items om verder te kijken.";
"No matches found" = "Geen overeenkomsten gevonden";
"No Module Selected" = "Geen Module Geselecteerd";
"No Modules" = "Geen Modules";
"No Results Found" = "Geen Resultaten Gevonden";
"No Search Results Found" = "Geen Zoekresultaten Gevonden";
"Nothing to Continue Watching" = "Niets om Verder te Kijken";
/* Notes and Messages */
"Note that the modules will be replaced only if there is a different version string inside the JSON file." = "Let op: de modules worden alleen vervangen als er een andere versiestring in het JSON-bestand staat.";
/* Actions */
"OK" = "OK";
"Open Community Library" = "Open Community Bibliotheek";
/* External Services */
"Open in AniList" = "Openen in AniList";
"Original Poster" = "Originele Poster";
/* Playback */
"Paused" = "Gepauzeerd";
"Play" = "Afspelen";
"Player" = "Speler";
/* System Messages */
"Please restart the app to apply the language change." = "Herstart de app om de taalwijziging toe te passen.";
"Please select a module from settings" = "Selecteer een module uit de instellingen";
/* Interface */
"Portrait Columns" = "Staande Kolommen";
"Progress bar Marker Color" = "Voortgangsbalk Markeerkleur";
"Provider: %@" = "Provider: %@";
/* Queue */
"Queue" = "Wachtrij";
"Queued" = "In Wachtrij";
/* Content */
"Recently watched content will appear here." = "Recent bekeken inhoud verschijnt hier.";
/* Settings */
"Refresh Modules on Launch" = "Ververs Modules bij Opstarten";
"Refresh Storage Info" = "Opslaginformatie Vernieuwen";
"Remember Playback speed" = "Onthoud Afspeelsnelheid";
/* Actions */
"Remove" = "Verwijderen";
"Remove All Cache" = "Verwijder Alle Cache";
/* File Management */
"Remove All Documents" = "Verwijder Alle Documenten";
"Remove Documents" = "Documenten Verwijderen";
"Remove Downloaded Media" = "Gedownloade Media Verwijderen";
"Remove Downloads" = "Verwijder Downloads";
"Remove from Bookmarks" = "Verwijderen uit Bladwijzers";
"Remove Item" = "Item Verwijderen";
/* Support */
"Report an Issue" = "Rapporteer een Probleem";
/* Reset Options */
"Reset" = "Resetten";
"Reset AniList ID" = "AniList ID Resetten";
"Reset Episode Progress" = "Afleveringsvoortgang Resetten";
"Reset progress" = "Voortgang resetten";
"Reset Progress" = "Voortgang Resetten";
/* System */
"Restart Required" = "Herstart Vereist";
"Running Sora %@ - cranci1" = "Sora %@ draait - cranci1";
/* Actions */
"Save" = "Opslaan";
"Search" = "Zoeken";
/* Search */
"Search downloads" = "Downloads zoeken";
"Search for something..." = "Zoek naar iets...";
"Search..." = "Zoeken...";
/* Content */
"Season %d" = "Seizoen %d";
"Season %lld" = "Seizoen %lld";
"Segments Color" = "Segmenten Kleur";
/* Modules */
"Select Module" = "Module Selecteren";
"Set Custom AniList ID" = "Aangepaste AniList ID Instellen";
/* Interface */
"Settings" = "Instellingen";
"Shadow" = "Schaduw";
"Show More (%lld more characters)" = "Meer Tonen (%lld meer tekens)";
"Show PiP Button" = "Toon PiP Knop";
"Show Skip 85s Button" = "Toon Overslaan 85s Knop";
"Show Skip Intro / Outro Buttons" = "Toon Overslaan Intro / Outro Knoppen";
"Shows" = "Series";
"Size (%@)" = "Grootte (%@)";
"Skip Settings" = "Overslaan Instellingen";
/* Player Features */
"Some features are limited to the Sora and Default player, such as ForceLandscape, holdSpeed and custom time skip increments." = "Sommige functies zijn beperkt tot de Sora en Standaard speler, zoals ForceLandscape, holdSpeed en aangepaste tijd overslaan stappen.";
/* App Info */
"Sora" = "Sora";
"Sora %@ by cranci1" = "Sora %@ door cranci1";
"Sora and cranci1 are not affiliated with AniList or Trakt in any way.\n\nAlso note that progress updates may not be 100% accurate." = "Sora en cranci1 zijn op geen enkele manier verbonden met AniList of Trakt.\n\nHoud er ook rekening mee dat voortgangsupdates mogelijk niet 100% nauwkeurig zijn.";
"Sora GitHub Repository" = "Sora GitHub Repository";
"Sora/Sulfur will always remain free with no ADs!" = "Sora/Sulfur blijft altijd gratis zonder advertenties!";
/* Interface */
"Sort" = "Sorteren";
"Speed Settings" = "Snelheidsinstellingen";
/* Playback */
"Start Watching" = "Start met Kijken";
"Start Watching Episode %d" = "Start met Kijken Aflevering %d";
"Storage Used" = "Gebruikte Opslag";
"Stream" = "Stream";
"Streaming and video playback." = "Streaming en video afspelen.";
/* Subtitles */
"Subtitle Color" = "Ondertitelingskleur";
"Subtitle Settings" = "Ondertitelingsinstellingen";
/* Sync */
"Sync anime progress" = "Synchroniseer anime voortgang";
"Sync TV shows progress" = "Synchroniseer TV series voortgang";
/* System */
"System" = "Systeem";
/* Instructions */
"Tap a title to override the current match." = "Tik op een titel om de huidige match te overschrijven.";
"Tap Skip" = "Tik Overslaan";
"Tap to manage your modules" = "Tik om je modules te beheren";
"Tap to select a module" = "Tik om een module te selecteren";
/* App Information */
"The app cache helps the app load images faster.\n\nClearing the Documents folder will delete all downloaded modules.\n\nDo not erase App Data unless you understand the consequences — it may cause the app to malfunction." = "De app cache helpt de app om afbeeldingen sneller te laden.\n\nHet wissen van de Documents map zal alle gedownloade modules verwijderen.\n\nWis de App Data niet tenzij je de gevolgen begrijpt — het kan ervoor zorgen dat de app niet meer goed werkt.";
"The episode range controls how many episodes appear on each page. Episodes are grouped into sets (like 125, 2650, and so on), allowing you to navigate through them more easily.\n\nFor episode metadata, it refers to the episode thumbnail and title, since sometimes it can contain spoilers." = "Het afleveringen bereik bepaalt hoeveel afleveringen er op elke pagina verschijnen. Afleveringen worden gegroepeerd in sets (zoals 1-25, 26-50, enzovoort), waardoor je er gemakkelijker doorheen kunt navigeren.\n\nVoor aflevering metadata verwijst dit naar de aflevering miniatuur en titel, aangezien deze soms spoilers kunnen bevatten.";
"The module provided only a single episode, this is most likely a movie, so we decided to make separate screens for these cases." = "De module heeft slechts één aflevering geleverd, dit is waarschijnlijk een film, daarom hebben we aparte schermen gemaakt voor deze gevallen.";
/* Interface */
"Thumbnails Width" = "Miniatuur Breedte";
"TMDB Match" = "TMDB Match";
"Trackers" = "Trackers";
"Trakt" = "Trakt";
"Trakt.tv" = "Trakt.tv";
/* Search */
"Try different keywords" = "Probeer andere zoekwoorden";
"Try different search terms" = "Probeer andere zoektermen";
/* Player Controls */
"Two Finger Hold for Pause" = "Twee Vingers Vasthouden voor Pauze";
"Unable to fetch matches. Please try again later." = "Kan geen matches ophalen. Probeer het later opnieuw.";
"Use TMDB Poster Image" = "TMDB Poster Afbeelding Gebruiken";
/* Version */
"v%@" = "v%@";
"Video Player" = "Videospeler";
/* Video Settings */
"Video Quality Preferences" = "Video Kwaliteit Voorkeuren";
"View All" = "Alles Bekijken";
"Watched" = "Bekeken";
"Why am I not seeing any episodes?" = "Waarom zie ik geen afleveringen?";
"WiFi Quality" = "WiFi Kwaliteit";
/* User Status */
"You are not logged in" = "Je bent niet ingelogd";
"You have no items saved." = "Je hebt geen items opgeslagen.";
"Your downloaded episodes will appear here" = "Je gedownloade afleveringen verschijnen hier";
"Your recently watched content will appear here" = "Je recent bekeken inhoud verschijnt hier";
/* Download Settings */
"Download Settings" = "Download Instellingen";
"Max concurrent downloads controls how many episodes can download simultaneously. Higher values may use more bandwidth and device resources." = "Maximum gelijktijdige downloads bepaalt hoeveel afleveringen tegelijk kunnen worden gedownload. Hogere waarden kunnen meer bandbreedte en apparaatbronnen gebruiken.";
"Quality" = "Kwaliteit";
"Max Concurrent Downloads" = "Maximum Gelijktijdige Downloads";
"Allow Cellular Downloads" = "Downloads via Mobiel Netwerk Toestaan";
"Quality Information" = "Kwaliteitsinformatie";
/* Storage */
"Storage Management" = "Opslagbeheer";
"Storage Used" = "Gebruikte Opslag";
"Library cleared successfully" = "Bibliotheek succesvol gewist";
"All downloads deleted successfully" = "Alle downloads succesvol verwijderd";

View file

@ -17,6 +17,10 @@
0457C59E2DE78267000AFBD9 /* BookmarkLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0457C59B2DE78267000AFBD9 /* BookmarkLink.swift */; };
0457C59F2DE78267000AFBD9 /* BookmarkGridItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0457C5992DE78267000AFBD9 /* BookmarkGridItemView.swift */; };
0457C5A12DE78385000AFBD9 /* BookmarksDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0457C5A02DE78385000AFBD9 /* BookmarksDetailView.swift */; };
0488FA952DFDE724007575E1 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 0488FA902DFDE724007575E1 /* Localizable.strings */; };
0488FA962DFDE724007575E1 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 0488FA932DFDE724007575E1 /* Localizable.strings */; };
0488FA9A2DFDF380007575E1 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 0488FA982DFDF380007575E1 /* Localizable.strings */; };
0488FA9E2DFDF3BB007575E1 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 0488FA9C2DFDF3BB007575E1 /* Localizable.strings */; };
04CD76DB2DE20F2200733536 /* AllWatching.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04CD76DA2DE20F2200733536 /* AllWatching.swift */; };
04EAC39A2DF9E0DB00BBD483 /* SplashScreenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04EAC3992DF9E0DB00BBD483 /* SplashScreenView.swift */; };
04F08EDC2DE10BF3006B29D9 /* ProgressiveBlurView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04F08EDB2DE10BEC006B29D9 /* ProgressiveBlurView.swift */; };
@ -36,7 +40,9 @@
132AF1252D9995F900A0140B /* JSController-Search.swift in Sources */ = {isa = PBXBuildFile; fileRef = 132AF1242D9995F900A0140B /* JSController-Search.swift */; };
13367ECC2DF70698009CB33F /* Nuke in Frameworks */ = {isa = PBXBuildFile; productRef = 13367ECB2DF70698009CB33F /* Nuke */; };
13367ECE2DF70698009CB33F /* NukeUI in Frameworks */ = {isa = PBXBuildFile; productRef = 13367ECD2DF70698009CB33F /* NukeUI */; };
13367ED02DF70819009CB33F /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 13367ECF2DF70819009CB33F /* Localizable.xcstrings */; };
133CF6A62DFEBE9000BD13F9 /* VideoWatchingActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 133CF6A32DFEBE8F00BD13F9 /* VideoWatchingActivity.swift */; };
133CF6A72DFEBE9000BD13F9 /* SharePlayManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 133CF6A42DFEBE8F00BD13F9 /* SharePlayManager.swift */; };
133CF6A82DFEBE9000BD13F9 /* SharePlayCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 133CF6A52DFEBE9000BD13F9 /* SharePlayCoordinator.swift */; };
133D7C6E2D2BE2500075467E /* SoraApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 133D7C6D2D2BE2500075467E /* SoraApp.swift */; };
133D7C702D2BE2500075467E /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 133D7C6F2D2BE2500075467E /* ContentView.swift */; };
133D7C722D2BE2520075467E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 133D7C712D2BE2520075467E /* Assets.xcassets */; };
@ -112,6 +118,10 @@
0457C59A2DE78267000AFBD9 /* BookmarkGridView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarkGridView.swift; sourceTree = "<group>"; };
0457C59B2DE78267000AFBD9 /* BookmarkLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarkLink.swift; sourceTree = "<group>"; };
0457C5A02DE78385000AFBD9 /* BookmarksDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarksDetailView.swift; sourceTree = "<group>"; };
0488FA8F2DFDE724007575E1 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = Localizable.strings; sourceTree = "<group>"; };
0488FA922DFDE724007575E1 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = Localizable.strings; sourceTree = "<group>"; };
0488FA992DFDF380007575E1 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = Localizable.strings; sourceTree = "<group>"; };
0488FA9D2DFDF3BB007575E1 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = Localizable.strings; sourceTree = "<group>"; };
04CD76DA2DE20F2200733536 /* AllWatching.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllWatching.swift; sourceTree = "<group>"; };
04EAC3992DF9E0DB00BBD483 /* SplashScreenView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplashScreenView.swift; sourceTree = "<group>"; };
04F08EDB2DE10BEC006B29D9 /* ProgressiveBlurView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressiveBlurView.swift; sourceTree = "<group>"; };
@ -130,7 +140,9 @@
132AF1202D99951700A0140B /* JSController-Streams.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "JSController-Streams.swift"; sourceTree = "<group>"; };
132AF1222D9995C300A0140B /* JSController-Details.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "JSController-Details.swift"; sourceTree = "<group>"; };
132AF1242D9995F900A0140B /* JSController-Search.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "JSController-Search.swift"; sourceTree = "<group>"; };
13367ECF2DF70819009CB33F /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Localizable.xcstrings; sourceTree = "<group>"; };
133CF6A32DFEBE8F00BD13F9 /* VideoWatchingActivity.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VideoWatchingActivity.swift; sourceTree = "<group>"; };
133CF6A42DFEBE8F00BD13F9 /* SharePlayManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SharePlayManager.swift; sourceTree = "<group>"; };
133CF6A52DFEBE9000BD13F9 /* SharePlayCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SharePlayCoordinator.swift; sourceTree = "<group>"; };
133D7C6A2D2BE2500075467E /* Sulfur.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Sulfur.app; sourceTree = BUILT_PRODUCTS_DIR; };
133D7C6D2D2BE2500075467E /* SoraApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SoraApp.swift; sourceTree = "<group>"; };
133D7C6F2D2BE2500075467E /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
@ -241,6 +253,38 @@
path = BookmarkComponents;
sourceTree = "<group>";
};
0488FA912DFDE724007575E1 /* en.lproj */ = {
isa = PBXGroup;
children = (
0488FA902DFDE724007575E1 /* Localizable.strings */,
);
path = en.lproj;
sourceTree = "<group>";
};
0488FA942DFDE724007575E1 /* nl.lproj */ = {
isa = PBXGroup;
children = (
0488FA932DFDE724007575E1 /* Localizable.strings */,
);
path = nl.lproj;
sourceTree = "<group>";
};
0488FA972DFDF334007575E1 /* fr.lproj */ = {
isa = PBXGroup;
children = (
0488FA982DFDF380007575E1 /* Localizable.strings */,
);
path = fr.lproj;
sourceTree = "<group>";
};
0488FA9B2DFDF385007575E1 /* ar.lproj */ = {
isa = PBXGroup;
children = (
0488FA9C2DFDF3BB007575E1 /* Localizable.strings */,
);
path = ar.lproj;
sourceTree = "<group>";
};
04F08EDA2DE10BE3006B29D9 /* ProgressiveBlurView */ = {
isa = PBXGroup;
children = (
@ -311,6 +355,27 @@
path = Analytics;
sourceTree = "<group>";
};
133CF6A22DFEBE8100BD13F9 /* SharePlay */ = {
isa = PBXGroup;
children = (
133CF6A42DFEBE8F00BD13F9 /* SharePlayManager.swift */,
133CF6A52DFEBE9000BD13F9 /* SharePlayCoordinator.swift */,
133CF6A32DFEBE8F00BD13F9 /* VideoWatchingActivity.swift */,
);
path = SharePlay;
sourceTree = "<group>";
};
133CF6A92DFEBEAB00BD13F9 /* MediaUtils */ = {
isa = PBXGroup;
children = (
133CF6A22DFEBE8100BD13F9 /* SharePlay */,
13DC0C442D302C6A00D0F966 /* NormalPlayer */,
13EA2BD02D32D97400C1EBD7 /* CustomPlayer */,
13C0E5E82D5F85DD00E7F619 /* ContinueWatching */,
);
path = MediaUtils;
sourceTree = "<group>";
};
133D7C612D2BE2500075467E = {
isa = PBXGroup;
children = (
@ -330,16 +395,20 @@
133D7C6C2D2BE2500075467E /* Sora */ = {
isa = PBXGroup;
children = (
0488FA942DFDE724007575E1 /* nl.lproj */,
0488FA912DFDE724007575E1 /* en.lproj */,
0488FA972DFDF334007575E1 /* fr.lproj */,
0488FA9B2DFDF385007575E1 /* ar.lproj */,
130C6BF82D53A4C200DC1432 /* Sora.entitlements */,
13DC0C412D2EC9BA00D0F966 /* Info.plist */,
13103E802D589D6C000F0673 /* Tracking Services */,
133D7C852D2BE2640075467E /* Utils */,
133CF6A92DFEBEAB00BD13F9 /* MediaUtils */,
133D7C7B2D2BE2630075467E /* Views */,
133D7C852D2BE2640075467E /* Utils */,
133D7C6D2D2BE2500075467E /* SoraApp.swift */,
133D7C6F2D2BE2500075467E /* ContentView.swift */,
133D7C712D2BE2520075467E /* Assets.xcassets */,
133D7C732D2BE2520075467E /* Preview Content */,
13367ECF2DF70819009CB33F /* Localizable.xcstrings */,
);
path = Sora;
sourceTree = "<group>";
@ -405,10 +474,8 @@
133D7C8A2D2BE2640075467E /* JSLoader */,
1327FBA52D758CEA00FC6689 /* Analytics */,
133D7C862D2BE2640075467E /* Extensions */,
13DC0C442D302C6A00D0F966 /* MediaPlayer */,
13103E8C2D58E037000F0673 /* SkeletonCells */,
72443C832DC8046500A61321 /* DownloadUtils */,
13C0E5E82D5F85DD00E7F619 /* ContinueWatching */,
);
path = Utils;
sourceTree = "<group>";
@ -552,14 +619,13 @@
path = Auth;
sourceTree = "<group>";
};
13DC0C442D302C6A00D0F966 /* MediaPlayer */ = {
13DC0C442D302C6A00D0F966 /* NormalPlayer */ = {
isa = PBXGroup;
children = (
13EA2BD02D32D97400C1EBD7 /* CustomPlayer */,
13DC0C452D302C7500D0F966 /* VideoPlayer.swift */,
13EA2BD82D32D98400C1EBD7 /* NormalPlayer.swift */,
);
path = MediaPlayer;
path = NormalPlayer;
sourceTree = "<group>";
};
13E62FBF2DABC3A20007E259 /* Trakt */ = {
@ -676,6 +742,9 @@
knownRegions = (
en,
Base,
nl,
fr,
ar,
);
mainGroup = 133D7C612D2BE2500075467E;
packageReferences = (
@ -698,9 +767,12 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0488FA9A2DFDF380007575E1 /* Localizable.strings in Resources */,
0488FA9E2DFDF3BB007575E1 /* Localizable.strings in Resources */,
133D7C752D2BE2520075467E /* Preview Assets.xcassets in Resources */,
133D7C722D2BE2520075467E /* Assets.xcassets in Resources */,
13367ED02DF70819009CB33F /* Localizable.xcstrings in Resources */,
0488FA952DFDE724007575E1 /* Localizable.strings in Resources */,
0488FA962DFDE724007575E1 /* Localizable.strings in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -759,6 +831,7 @@
138AA1B82D2D66FD0021F9DF /* EpisodeCell.swift in Sources */,
722248662DCBC13E00CABE2D /* JSController-Downloads.swift in Sources */,
133D7C8C2D2BE2640075467E /* SearchView.swift in Sources */,
133CF6A62DFEBE9000BD13F9 /* VideoWatchingActivity.swift in Sources */,
13DB468E2D90093A008CBC03 /* Anilist-Token.swift in Sources */,
1EAC7A322D888BC50083984D /* MusicProgressSlider.swift in Sources */,
722248632DCBAA4700CABE2D /* JSController-HeaderManager.swift in Sources */,
@ -766,6 +839,7 @@
133D7C922D2BE2640075467E /* URLSession.swift in Sources */,
0457C5A12DE78385000AFBD9 /* BookmarksDetailView.swift in Sources */,
133D7C912D2BE2640075467E /* SettingsViewModule.swift in Sources */,
133CF6A82DFEBE9000BD13F9 /* SharePlayCoordinator.swift in Sources */,
13E62FC22DABC5830007E259 /* Trakt-Login.swift in Sources */,
133F55BB2D33B55100E08EEA /* LibraryManager.swift in Sources */,
13E62FC42DABC58C0007E259 /* Trakt-Token.swift in Sources */,
@ -793,6 +867,7 @@
13C0E5EA2D5F85EA00E7F619 /* ContinueWatchingManager.swift in Sources */,
13637B8A2DE0EA1100BDA2FC /* UserDefaults.swift in Sources */,
0457C59D2DE78267000AFBD9 /* BookmarkGridView.swift in Sources */,
133CF6A72DFEBE9000BD13F9 /* SharePlayManager.swift in Sources */,
0457C59E2DE78267000AFBD9 /* BookmarkLink.swift in Sources */,
0457C59F2DE78267000AFBD9 /* BookmarkGridItemView.swift in Sources */,
);
@ -800,6 +875,41 @@
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
0488FA902DFDE724007575E1 /* Localizable.strings */ = {
isa = PBXVariantGroup;
children = (
0488FA8F2DFDE724007575E1 /* en */,
);
name = Localizable.strings;
sourceTree = "<group>";
};
0488FA932DFDE724007575E1 /* Localizable.strings */ = {
isa = PBXVariantGroup;
children = (
0488FA922DFDE724007575E1 /* nl */,
);
name = Localizable.strings;
sourceTree = "<group>";
};
0488FA982DFDF380007575E1 /* Localizable.strings */ = {
isa = PBXVariantGroup;
children = (
0488FA992DFDF380007575E1 /* fr */,
);
name = Localizable.strings;
sourceTree = "<group>";
};
0488FA9C2DFDF3BB007575E1 /* Localizable.strings */ = {
isa = PBXVariantGroup;
children = (
0488FA9D2DFDF3BB007575E1 /* ar */,
);
name = Localizable.strings;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
133D7C762D2BE2520075467E /* Debug */ = {
isa = XCBuildConfiguration;