diff --git a/composeApp/src/androidFull/kotlin/com/nuvio/app/features/trailer/YoutubeChunkedDataSourceFactory.kt b/composeApp/src/androidFull/kotlin/com/nuvio/app/features/trailer/YoutubeChunkedDataSourceFactory.kt
index 5d93ab92..79335c17 100644
--- a/composeApp/src/androidFull/kotlin/com/nuvio/app/features/trailer/YoutubeChunkedDataSourceFactory.kt
+++ b/composeApp/src/androidFull/kotlin/com/nuvio/app/features/trailer/YoutubeChunkedDataSourceFactory.kt
@@ -8,6 +8,10 @@ import androidx.media3.datasource.DataSource
import androidx.media3.datasource.DataSpec
import androidx.media3.datasource.DefaultHttpDataSource
import androidx.media3.datasource.TransferListener
+import kotlinx.coroutines.runBlocking
+import nuvio.composeapp.generated.resources.Res
+import nuvio.composeapp.generated.resources.player_error_unable_to_play_stream
+import org.jetbrains.compose.resources.getString
/**
* A DataSource.Factory that wraps DefaultHttpDataSource and appends YouTube's
@@ -75,7 +79,9 @@ class YoutubeChunkedDataSourceFactory(
}
private fun openNextChunk(): Long {
- val spec = originalDataSpec ?: throw IllegalStateException("No DataSpec")
+ val spec = originalDataSpec ?: throw IllegalStateException(
+ runBlocking { getString(Res.string.player_error_unable_to_play_stream) },
+ )
val end = if (totalContentLength != C.LENGTH_UNSET.toLong()) {
minOf(currentChunkStart + chunkSize - 1, currentChunkStart + totalContentLength - 1)
} else {
diff --git a/composeApp/src/commonMain/composeResources/values-fr/strings.xml b/composeApp/src/commonMain/composeResources/values-fr/strings.xml
index 15301839..22de317f 100644
--- a/composeApp/src/commonMain/composeResources/values-fr/strings.xml
+++ b/composeApp/src/commonMain/composeResources/values-fr/strings.xml
@@ -1192,4 +1192,17 @@
Ko
Mo
Go
+ %1$d h %2$d min
+ %1$d h
+ %1$d min
+ Aucun résultat de recherche pour %1$s.
+ Ce dépôt de plugin est déjà installé.
+ Impossible d’installer le dépôt de plugin
+ Impossible d’actualiser le dépôt
+ Le nom du manifeste est manquant.
+ La version du manifeste est manquante.
+ Le manifeste ne contient aucun fournisseur.
+ Champ « %1$s » manquant dans le manifeste
+ Moteur de lecture MPV indisponible. Reconstruis l’app.
+ Impossible de lire ce flux.
diff --git a/composeApp/src/commonMain/composeResources/values/strings.xml b/composeApp/src/commonMain/composeResources/values/strings.xml
index cd8a97e2..dc4d8771 100644
--- a/composeApp/src/commonMain/composeResources/values/strings.xml
+++ b/composeApp/src/commonMain/composeResources/values/strings.xml
@@ -1272,4 +1272,17 @@
KB
MB
GB
+ %1$dh %2$dm
+ %1$dh
+ %1$dm
+ No search results returned for %1$s.
+ That plugin repository is already installed.
+ Unable to install plugin repository
+ Unable to refresh repository
+ Manifest name is missing.
+ Manifest version is missing.
+ Manifest has no providers.
+ Manifest missing \"%1$s\"
+ MPV player engine not available. Please rebuild the app.
+ Unable to play this stream.
diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/addons/AddonManifestParser.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/addons/AddonManifestParser.kt
index 414c4cf1..48634dcc 100644
--- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/addons/AddonManifestParser.kt
+++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/addons/AddonManifestParser.kt
@@ -1,5 +1,6 @@
package com.nuvio.app.features.addons
+import kotlinx.coroutines.runBlocking
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonArray
import kotlinx.serialization.json.JsonObject
@@ -8,6 +9,9 @@ import kotlinx.serialization.json.booleanOrNull
import kotlinx.serialization.json.contentOrNull
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive
+import nuvio.composeapp.generated.resources.Res
+import nuvio.composeapp.generated.resources.addons_manifest_missing_field
+import org.jetbrains.compose.resources.getString
internal object AddonManifestParser {
private val json = Json {
@@ -92,7 +96,9 @@ internal object AddonManifestParser {
private fun JsonObject.requiredString(name: String): String =
optionalString(name)?.takeIf { it.isNotBlank() }
- ?: throw IllegalArgumentException("Manifest missing \"$name\"")
+ ?: throw IllegalArgumentException(
+ runBlocking { getString(Res.string.addons_manifest_missing_field, name) },
+ )
private fun JsonObject.optionalString(name: String): String? =
this[name]?.jsonPrimitive?.contentOrNull
diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/details/RuntimeFormat.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/details/RuntimeFormat.kt
index 375cba10..05704df9 100644
--- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/details/RuntimeFormat.kt
+++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/details/RuntimeFormat.kt
@@ -1,5 +1,12 @@
package com.nuvio.app.features.details
+import kotlinx.coroutines.runBlocking
+import nuvio.composeapp.generated.resources.Res
+import nuvio.composeapp.generated.resources.details_runtime_hours_minutes
+import nuvio.composeapp.generated.resources.details_runtime_hours_only
+import nuvio.composeapp.generated.resources.details_runtime_minutes_only
+import org.jetbrains.compose.resources.getString
+
private val hourTokenRegex = Regex("""(?i)(\d+)\s*h(?:ours?)?""")
private val minuteTokenRegex = Regex("""(?i)(\d+)\s*m(?:in(?:ute)?s?)?""")
private val hourMinuteColonRegex = Regex("""^\s*(\d+)\s*:\s*(\d{1,2})\s*$""")
@@ -16,10 +23,12 @@ internal fun formatRuntimeFromMinutes(totalMinutes: Int): String {
val hours = totalMinutes / 60
val minutes = totalMinutes % 60
- return when {
- hours > 0 && minutes > 0 -> "${hours}h ${minutes}m"
- hours > 0 -> "${hours}h"
- else -> "${minutes}m"
+ return runBlocking {
+ when {
+ hours > 0 && minutes > 0 -> getString(Res.string.details_runtime_hours_minutes, hours, minutes)
+ hours > 0 -> getString(Res.string.details_runtime_hours_only, hours)
+ else -> getString(Res.string.details_runtime_minutes_only, minutes)
+ }
}
}
diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/search/SearchRepository.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/search/SearchRepository.kt
index b71d97a2..f7137da1 100644
--- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/search/SearchRepository.kt
+++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/search/SearchRepository.kt
@@ -327,7 +327,9 @@ object SearchRepository {
search = query,
).withUnreleasedFilter()
val items = page.items
- require(items.isNotEmpty()) { "No search results returned for $catalogName." }
+ require(items.isNotEmpty()) {
+ getString(Res.string.search_error_no_results_for_catalog, catalogName)
+ }
return HomeCatalogSection(
key = "${manifest.id}:search:$type:$catalogId:${query.lowercase()}",
diff --git a/composeApp/src/fullCommonMain/kotlin/com/nuvio/app/features/plugins/PluginManifestParser.kt b/composeApp/src/fullCommonMain/kotlin/com/nuvio/app/features/plugins/PluginManifestParser.kt
index d8b00417..7981f311 100644
--- a/composeApp/src/fullCommonMain/kotlin/com/nuvio/app/features/plugins/PluginManifestParser.kt
+++ b/composeApp/src/fullCommonMain/kotlin/com/nuvio/app/features/plugins/PluginManifestParser.kt
@@ -1,6 +1,12 @@
package com.nuvio.app.features.plugins
+import kotlinx.coroutines.runBlocking
import kotlinx.serialization.json.Json
+import nuvio.composeapp.generated.resources.Res
+import nuvio.composeapp.generated.resources.plugins_manifest_name_missing
+import nuvio.composeapp.generated.resources.plugins_manifest_no_providers
+import nuvio.composeapp.generated.resources.plugins_manifest_version_missing
+import org.jetbrains.compose.resources.getString
internal object PluginManifestParser {
private val json = Json {
@@ -9,9 +15,15 @@ internal object PluginManifestParser {
fun parse(payload: String): PluginManifest {
val manifest = json.decodeFromString(payload)
- require(manifest.name.isNotBlank()) { "Manifest name is missing." }
- require(manifest.version.isNotBlank()) { "Manifest version is missing." }
- require(manifest.scrapers.isNotEmpty()) { "Manifest has no providers." }
+ require(manifest.name.isNotBlank()) {
+ runBlocking { getString(Res.string.plugins_manifest_name_missing) }
+ }
+ require(manifest.version.isNotBlank()) {
+ runBlocking { getString(Res.string.plugins_manifest_version_missing) }
+ }
+ require(manifest.scrapers.isNotEmpty()) {
+ runBlocking { getString(Res.string.plugins_manifest_no_providers) }
+ }
return manifest
}
}
diff --git a/composeApp/src/fullCommonMain/kotlin/com/nuvio/app/features/plugins/PluginRepository.kt b/composeApp/src/fullCommonMain/kotlin/com/nuvio/app/features/plugins/PluginRepository.kt
index 32e0562f..85bdad69 100644
--- a/composeApp/src/fullCommonMain/kotlin/com/nuvio/app/features/plugins/PluginRepository.kt
+++ b/composeApp/src/fullCommonMain/kotlin/com/nuvio/app/features/plugins/PluginRepository.kt
@@ -17,6 +17,7 @@ import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
+import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@@ -25,6 +26,11 @@ import kotlinx.serialization.json.Json
import kotlinx.serialization.json.buildJsonObject
import kotlinx.serialization.json.encodeToJsonElement
import kotlinx.serialization.json.put
+import nuvio.composeapp.generated.resources.Res
+import nuvio.composeapp.generated.resources.plugins_repository_already_installed
+import nuvio.composeapp.generated.resources.plugins_repository_install_failed
+import nuvio.composeapp.generated.resources.plugins_repository_refresh_failed
+import org.jetbrains.compose.resources.getString
@Serializable
private data class PluginRow(
@@ -149,7 +155,7 @@ actual object PluginRepository {
}
if (_uiState.value.repositories.any { it.manifestUrl == manifestUrl }) {
- return AddPluginRepositoryResult.Error("That plugin repository is already installed.")
+ return AddPluginRepositoryResult.Error(getString(Res.string.plugins_repository_already_installed))
}
return try {
@@ -168,7 +174,7 @@ actual object PluginRepository {
pushToServer()
AddPluginRepositoryResult.Success(repo)
} catch (error: Throwable) {
- AddPluginRepositoryResult.Error(error.message ?: "Unable to install plugin repository")
+ AddPluginRepositoryResult.Error(error.message ?: getString(Res.string.plugins_repository_install_failed))
}
}
@@ -232,7 +238,7 @@ actual object PluginRepository {
if (existing.manifestUrl == manifestUrl) {
existing.copy(
isRefreshing = false,
- errorMessage = error.message ?: "Unable to refresh repository",
+ errorMessage = error.message ?: runBlocking { getString(Res.string.plugins_repository_refresh_failed) },
)
} else {
existing
diff --git a/composeApp/src/iosMain/kotlin/com/nuvio/app/features/player/PlayerEngine.ios.kt b/composeApp/src/iosMain/kotlin/com/nuvio/app/features/player/PlayerEngine.ios.kt
index 2877b04c..5bafb9fc 100644
--- a/composeApp/src/iosMain/kotlin/com/nuvio/app/features/player/PlayerEngine.ios.kt
+++ b/composeApp/src/iosMain/kotlin/com/nuvio/app/features/player/PlayerEngine.ios.kt
@@ -14,6 +14,9 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
+import nuvio.composeapp.generated.resources.Res
+import nuvio.composeapp.generated.resources.player_error_mpv_unavailable
+import org.jetbrains.compose.resources.getString
private const val TAG = "NuvioiOSPlayer"
@@ -44,7 +47,7 @@ actual fun PlatformPlayerSurface(
if (bridge == null) {
LaunchedEffect(Unit) {
- latestOnError.value("MPV player engine not available. Please rebuild the app.")
+ latestOnError.value(getString(Res.string.player_error_mpv_unavailable))
}
return
}