diff --git a/app/src/main/kotlin/me/eternal/purrfectsnap/bridge/BridgeService.kt b/app/src/main/kotlin/me/eternal/purrfectsnap/bridge/BridgeService.kt index aedc7f22..1fe9fcb7 100644 --- a/app/src/main/kotlin/me/eternal/purrfectsnap/bridge/BridgeService.kt +++ b/app/src/main/kotlin/me/eternal/purrfectsnap/bridge/BridgeService.kt @@ -121,7 +121,7 @@ class BridgeService : Service() { val pendingTask = remoteSideContext.taskManager.createPendingTask( Task( type = TaskType.DOWNLOAD, - title = "Media conversion", + title = remoteSideContext.translation["task_media_conversion_title"], author = null, hash = taskId ) diff --git a/app/src/main/kotlin/me/eternal/purrfectsnap/download/call/CallDownloadSessionImpl.kt b/app/src/main/kotlin/me/eternal/purrfectsnap/download/call/CallDownloadSessionImpl.kt index cfb86806..f437a875 100644 --- a/app/src/main/kotlin/me/eternal/purrfectsnap/download/call/CallDownloadSessionImpl.kt +++ b/app/src/main/kotlin/me/eternal/purrfectsnap/download/call/CallDownloadSessionImpl.kt @@ -120,7 +120,7 @@ class CallDownloadSessionImpl( val pendingTask = context.taskManager.createPendingTask( Task( type = TaskType.DOWNLOAD, - title = "Call Recording $author", + title = context.translation.format("task_call_recording_title", "author" to author), author = author, hash = UUID.randomUUID().toString() ) @@ -188,4 +188,4 @@ class CallDownloadSessionImpl( context.log.verbose("ending call") } } -} \ No newline at end of file +} diff --git a/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/MainActivity.kt b/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/MainActivity.kt index c6eeceda..8c4bb724 100644 --- a/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/MainActivity.kt +++ b/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/MainActivity.kt @@ -132,16 +132,16 @@ class MainActivity : ComponentActivity() { if (shouldShowAbiWarning) { AestheticDialog( onDismissRequest = {}, - title = "Wrong APK installed", + title = managerContext.translation["wrong_apk_title"], text = "", icon = Icons.Filled.Warning, - confirmButtonText = "Close", + confirmButtonText = managerContext.translation["common.close"], onConfirm = { (context as? Activity)?.finishAffinity() }, showCloseButton = false, opaque = true, customContent = { Text( - text = "Your device is armv8, please download the armv8 apk, not armv7.", + text = managerContext.translation["wrong_apk_message"], color = PurrfectPalette.textSecondary, lineHeight = 18.sp ) diff --git a/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/ManageReposSection.kt b/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/ManageReposSection.kt index faeab3b5..d8f3535e 100644 --- a/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/ManageReposSection.kt +++ b/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/ManageReposSection.kt @@ -143,7 +143,7 @@ class ManageReposSection: Routes.Route() { addRepo(url) }.onFailure { context.log.error("Failed to add repository", it) - context.shortToast(translation.format("add_repo_failed", "message" to (it.message ?: "Unknown"))) + context.shortToast(translation.format("add_repo_failed", "message" to (it.message ?: context.translation["common.unknown"]))) } loading = false } diff --git a/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/features/ConfigExportSummaryScreen.kt b/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/features/ConfigExportSummaryScreen.kt index 9fc9593b..5edc1c4e 100644 --- a/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/features/ConfigExportSummaryScreen.kt +++ b/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/features/ConfigExportSummaryScreen.kt @@ -138,7 +138,7 @@ class ConfigExportSummaryScreen : Routes.Route() { override val content: @Composable (androidx.navigation.NavBackStackEntry) -> Unit = { val exportSensitiveData = it.arguments?.getString("exportSensitiveData")?.toBoolean() ?: false val includeSavedLocations = it.arguments?.getString("includeSavedLocations")?.toBoolean() ?: false - val exportLabel = context.translation["manager.sections.features.export_option"] ?: "Export" + val exportLabel = context.translation["manager.sections.features.export_option"] val parser = remember { ConfigParser() } val savedLocations = remember { if (includeSavedLocations) context.database.getLocationCoordinates() else null @@ -196,14 +196,14 @@ class ConfigExportSummaryScreen : Routes.Route() { tint = Color.White, modifier = Modifier.padding(end = 6.dp) ) - Text(context.translation["common.back"] ?: "Back") + Text(context.translation["common.back"]) } Box( modifier = Modifier.weight(1f), contentAlignment = Alignment.Center ) { Text( - text = "Summary", + text = translation["title"], color = Color.White, fontWeight = FontWeight.ExtraBold, fontSize = 18.sp diff --git a/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/features/ConfigImportConfirmationScreen.kt b/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/features/ConfigImportConfirmationScreen.kt index c22b3bd2..c06bd7c1 100644 --- a/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/features/ConfigImportConfirmationScreen.kt +++ b/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/features/ConfigImportConfirmationScreen.kt @@ -232,7 +232,7 @@ class ConfigImportConfirmationScreen : Routes.Route() { routes.configJsonForImport?.let { parser.parse(it) } ?: emptyMap() } val expandedState = remember { mutableStateMapOf() } - val importLabel = translation["confirm_button"] ?: "Import" + val importLabel = translation["confirm_button"] Box( modifier = Modifier @@ -281,14 +281,14 @@ class ConfigImportConfirmationScreen : Routes.Route() { tint = Color.White, modifier = Modifier.padding(end = 6.dp) ) - Text(context.translation["common.back"] ?: "Back") + Text(context.translation["common.back"]) } Box( modifier = Modifier.weight(1f), contentAlignment = Alignment.Center ) { Text( - text = "Summary", + text = translation["title"], color = Color.White, fontWeight = FontWeight.ExtraBold, fontSize = 18.sp @@ -308,7 +308,7 @@ class ConfigImportConfirmationScreen : Routes.Route() { context.longToast( context.translation.format( "config_import_failure_toast", - "error" to (err.message ?: "Unknown error") + "error" to (err.message ?: context.translation["common.unknown_error"]) ) ) } diff --git a/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/features/FeaturesRootSection.kt b/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/features/FeaturesRootSection.kt index fb7817c8..ca1ad21e 100644 --- a/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/features/FeaturesRootSection.kt +++ b/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/features/FeaturesRootSection.kt @@ -112,7 +112,7 @@ class FeaturesRootSection : Routes.Route() { } ?: routeInfo.translatedKey?.value } SEARCH_FEATURE_ROUTE -> { - translation["search_button"] ?: "Search" + translation["search_button"] } else -> { routeInfo.translatedKey?.value @@ -668,7 +668,7 @@ class FeaturesRootSection : Routes.Route() { border = BorderStroke(1.dp, Color.White.copy(alpha = 0.12f)) ) { Text( - text = "$messageCount messages", + text = translation.format("search_results_count", "count" to messageCount.toString()), modifier = Modifier.padding(horizontal = 10.dp, vertical = 6.dp), style = MaterialTheme.typography.bodyMedium, color = Color.White @@ -1014,7 +1014,7 @@ class FeaturesRootSection : Routes.Route() { }, placeholder = { Text( - text = translation["search_button"] ?: "Search", + text = translation["search_button"], color = Color(0xFFE0DCFF) ) }, @@ -1109,7 +1109,7 @@ class FeaturesRootSection : Routes.Route() { verticalAlignment = Alignment.CenterVertically ) { Text( - text = "Include Saved Locations", + text = context.translation["include_saved_locations"], style = MaterialTheme.typography.bodyMedium, color = Color.White ) @@ -1310,7 +1310,7 @@ class FeaturesRootSection : Routes.Route() { val headerTitle = activeSectionTitle ?: translation["manager.routes.features"] val subtitleText = when { - isSearchResults -> translation["search_button"] ?: "Search" + isSearchResults -> translation["search_button"] !activeSectionSubtitle.isNullOrBlank() -> activeSectionSubtitle else -> translation["manager.sections.features.subtitle"] ?: "" } @@ -1364,7 +1364,7 @@ class FeaturesRootSection : Routes.Route() { IconButton(onClick = onBack) { Icon( imageVector = Icons.AutoMirrored.Filled.ArrowBack, - contentDescription = translation["button.back"] ?: "Back", + contentDescription = context.translation["common.back"], tint = Color.White ) } @@ -1385,7 +1385,7 @@ class FeaturesRootSection : Routes.Route() { .weight(1f) .focusRequester(focusRequester), singleLine = true, - placeholder = { Text(text = translation["search_button"] ?: "Search", color = Color(0xFFE0DCFF)) }, + placeholder = { Text(text = translation["search_button"], color = Color(0xFFE0DCFF)) }, leadingIcon = { Icon( imageVector = Icons.Filled.Search, @@ -1543,7 +1543,7 @@ class FeaturesRootSection : Routes.Route() { ) { Icon(Icons.Filled.Delete, contentDescription = null, tint = Color.White.copy(alpha = 0.85f)) Spacer(Modifier.width(6.dp)) - Text(text = translation["clear_history"] ?: "Clear history", color = Color.White) + Text(text = translation["clear_history"], color = Color.White) } } } diff --git a/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/features/ManageRuleFeature.kt b/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/features/ManageRuleFeature.kt index e7687079..8bac3ca2 100644 --- a/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/features/ManageRuleFeature.kt +++ b/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/features/ManageRuleFeature.kt @@ -203,8 +203,8 @@ class ManageRuleFeature : Routes.Route() { title = translation["clear_list_button"], text = translation["dialog_clear_confirmation_text"], icon = Icons.Default.DeleteSweep, - confirmButtonText = context.translation["clear"], - dismissButtonText = context.translation["button.cancel"], + confirmButtonText = translation["dialog_clear_confirm_button"], + dismissButtonText = translation["dialog_clear_cancel_button"], onDismiss = { confirmationDialog = false }, onConfirm = { context.database.clearRuleIds(currentRuleType.key) @@ -390,7 +390,7 @@ class ManageRuleFeature : Routes.Route() { contentColor = Color.White ) ) { - Text(text = context.translation["clear"]) + Text(text = translation["dialog_clear_confirm_button"]) } } } diff --git a/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/home/HomeLogs.kt b/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/home/HomeLogs.kt index 75477b96..d82d5ce4 100644 --- a/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/home/HomeLogs.kt +++ b/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/home/HomeLogs.kt @@ -315,7 +315,7 @@ class HomeLogs : Routes.Route() { Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null, tint = Color.White) } Text( - text = routeInfo.translatedKey?.value ?: translation["manager.routes.home_logs"] ?: "Logs", + text = routeInfo.translatedKey?.value ?: translation["manager.routes.home_logs"], color = PurrfectPalette.textPrimary, fontSize = 18.sp, fontWeight = FontWeight.ExtraBold @@ -412,7 +412,7 @@ class HomeLogs : Routes.Route() { textAlign = TextAlign.Center ) Text( - text = "Pull to refresh or trigger an action to see new entries.", + text = translation["refresh_hint"], color = PurrfectPalette.textSecondary, fontSize = 13.sp, textAlign = TextAlign.Center, diff --git a/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/home/HomeSettings.kt b/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/home/HomeSettings.kt index b5e12922..d0246b01 100644 --- a/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/home/HomeSettings.kt +++ b/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/home/HomeSettings.kt @@ -154,8 +154,8 @@ class HomeSettings : Routes.Route() { var value by remember { mutableStateOf(sharedPreferences.getBoolean(realKey, defaultValue)) } var showDisableDialog by remember { mutableStateOf(false) } val hapticFeedback = LocalHapticFeedback.current - val positiveLabel = context.translation["button.positive"] ?: "Yes" - val negativeLabel = context.translation["button.negative"] ?: "No" + val positiveLabel = context.translation["button.positive"] + val negativeLabel = context.translation["button.negative"] LaunchedEffect(realKey) { if (!sharedPreferences.contains(realKey)) { @@ -167,7 +167,7 @@ class HomeSettings : Routes.Route() { if (showDisableDialog) { AestheticDialog( onDismissRequest = { showDisableDialog = false }, - title = confirmDisableTitle ?: "Are you sure?", + title = confirmDisableTitle ?: translation["reset_setup_dialog_title"], text = confirmDisableText.orEmpty(), icon = Icons.Filled.Warning, confirmButtonText = positiveLabel, @@ -313,9 +313,9 @@ class HomeSettings : Routes.Route() { val contextC = LocalContext.current val scope = rememberCoroutineScope() val scrollState = rememberScrollState() - val positiveLabel = context.translation["button.positive"] ?: "Yes" - val negativeLabel = context.translation["button.negative"] ?: "No" - val importLabel = context.translation["button.import"] ?: "Import" + val positiveLabel = context.translation["button.positive"] + val negativeLabel = context.translation["button.negative"] + val importLabel = context.translation["button.import"] val sharedButtonColors = ButtonDefaults.buttonColors( containerColor = Color.White.copy(alpha = 0.12f), contentColor = Color.White diff --git a/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/location/BetterLocationRoot.kt b/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/location/BetterLocationRoot.kt index c89c6338..a0419fad 100644 --- a/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/location/BetterLocationRoot.kt +++ b/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/location/BetterLocationRoot.kt @@ -127,7 +127,11 @@ class BetterLocationRoot : Routes.Route() { overflow = TextOverflow.Ellipsis ) Text( - text = "Lat ${friendLocation.latitude.toFloat()}, Lng ${friendLocation.longitude.toFloat()}", + text = context.translation.format( + "spoofed_coordinates_title", + "latitude" to friendLocation.latitude.toFloat().toString(), + "longitude" to friendLocation.longitude.toFloat().toString() + ), fontSize = 11.sp, fontWeight = FontWeight.Light, color = Color.White.copy(alpha = 0.8f) diff --git a/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/scripting/ManageScriptReposSection.kt b/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/scripting/ManageScriptReposSection.kt index 7f304124..26107c5f 100644 --- a/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/scripting/ManageScriptReposSection.kt +++ b/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/scripting/ManageScriptReposSection.kt @@ -255,7 +255,7 @@ class ManageScriptReposSection : Routes.Route() { } }.onFailure { context.log.error("Failed to add repository", it) - context.shortToast(translation.format("add_repo_failed_toast", "message" to (it.message ?: "Unknown"))) + context.shortToast(translation.format("add_repo_failed_toast", "message" to (it.message ?: context.translation["common.unknown"]))) } loading = false } @@ -292,7 +292,7 @@ class ManageScriptReposSection : Routes.Route() { .background(PurrfectPalette.backgroundGradient) ) { FloatingTopBar( - title = routeInfo.translatedKey?.value ?: (translation["title"] ?: "Repositories"), + title = routeInfo.translatedKey?.value ?: translation["title"], onBack = { routes.navController.popBackStack() }, modifier = Modifier .zIndex(2f) diff --git a/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/scripting/ScriptCatalog.kt b/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/scripting/ScriptCatalog.kt index 824344da..c6666f12 100644 --- a/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/scripting/ScriptCatalog.kt +++ b/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/scripting/ScriptCatalog.kt @@ -162,7 +162,7 @@ fun ScriptCatalog(root: ScriptingRootSection) { } } catch (e: Exception) { withContext(Dispatchers.Main) { - context.shortToast(translation.format("error", "message" to (e.localizedMessage ?: "Unknown"))) + context.shortToast(translation.format("error", "message" to (e.localizedMessage ?: context.translation["common.unknown"]))) } } } @@ -238,7 +238,7 @@ fun ScriptCatalog(root: ScriptingRootSection) { color = Color.White ) Text( - text = translation["loading"] ?: "Loading...", + text = translation["loading"], color = Color.White, fontWeight = FontWeight.SemiBold, fontSize = 13.sp @@ -348,7 +348,7 @@ fun ScriptCatalog(root: ScriptingRootSection) { border = BorderStroke(1.dp, Color.White.copy(alpha = 0.12f)) ) { Text( - text = translation.format("version", "version" to (entry.version ?: "N/A")), + text = translation.format("version", "version" to (entry.version ?: context.translation["common.not_available"])), modifier = Modifier.padding(horizontal = 10.dp, vertical = 6.dp), fontWeight = FontWeight.Medium, fontSize = 11.sp, diff --git a/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/scripting/ScriptingRootSection.kt b/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/scripting/ScriptingRootSection.kt index 3209b9a2..7e54f610 100644 --- a/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/scripting/ScriptingRootSection.kt +++ b/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/scripting/ScriptingRootSection.kt @@ -140,7 +140,7 @@ class ScriptingRootSection : Routes.Route() { return@launch }.onFailure { context.log.error("Failed to import script", it) - context.shortToast(translation.format("import_failed", "message" to (it.message ?: "Unknown"))) + context.shortToast(translation.format("import_failed", "message" to (it.message ?: context.translation["common.unknown"]))) } isLoading = false } @@ -431,7 +431,7 @@ class ScriptingRootSection : Routes.Route() { @Composable private fun SelectFolderButton(onClick: () -> Unit) { - val label = translation.getOrNull("select_folder_button") ?: "Select folder" + val label = translation["select_folder_button"] Box( modifier = Modifier .fillMaxWidth() @@ -439,13 +439,13 @@ class ScriptingRootSection : Routes.Route() { contentAlignment = Alignment.Center ) { Surface( - modifier = Modifier.size(68.dp), + modifier = Modifier.size(78.dp), shape = CircleShape, - color = Color.White.copy(alpha = 0.1f), + color = PurrfectPalette.cardOverlayColor.copy(alpha = 0.9f), tonalElevation = 0.dp, - shadowElevation = 10.dp, + shadowElevation = 14.dp, border = BorderStroke( - 1.dp, + 1.5.dp, Brush.linearGradient( listOf( PurrfectPalette.glowPrimary.copy(alpha = 0.7f), @@ -456,17 +456,18 @@ class ScriptingRootSection : Routes.Route() { ) { Box( modifier = Modifier - .fillMaxSize() + .padding(6.dp) + .size(66.dp) .clip(CircleShape) .background( Brush.radialGradient( colors = listOf( - PurrfectPalette.glowPrimary.copy(alpha = 0.335f), - PurrfectPalette.glowSecondary.copy(alpha = 0.25f), - Color.Transparent + PurrfectPalette.glowPrimary.copy(alpha = 0.42f), + PurrfectPalette.glowSecondary.copy(alpha = 0.34f) ) ) ) + .border(1.dp, Color.White.copy(alpha = 0.14f), CircleShape) .clickable(onClick = onClick), contentAlignment = Alignment.Center ) { @@ -474,7 +475,7 @@ class ScriptingRootSection : Routes.Route() { imageVector = Icons.AutoMirrored.Filled.ArrowForward, contentDescription = label, tint = Color.White, - modifier = Modifier.size(32.dp) + modifier = Modifier.size(34.dp) ) } } @@ -627,7 +628,7 @@ class ScriptingRootSection : Routes.Route() { Box( modifier = Modifier .fillMaxWidth() - .height(260.dp), + .heightIn(min = 260.dp), contentAlignment = Alignment.Center ) { Surface( @@ -743,7 +744,7 @@ class ScriptingRootSection : Routes.Route() { title = context.translation["manager.dialogs.scripting_warning.title"], text = context.translation["manager.dialogs.scripting_warning.content"], icon = Icons.Default.Warning, - confirmButtonText = translation["button.ok"] ?: "OK", + confirmButtonText = translation["button.ok"], onConfirm = { if (timeout == 0) scriptingWarning = false }, loading = timeout > 0, showCloseButton = false, @@ -875,7 +876,7 @@ class ScriptingRootSection : Routes.Route() { verticalArrangement = Arrangement.spacedBy(4.dp) ) { Text( - text = translation["manager.routes.scripts"] ?: "Scripts", + text = translation["manager.routes.scripts"], color = Color.White, fontWeight = FontWeight.ExtraBold, fontSize = 18.sp diff --git a/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/social/AddFriendDialog.kt b/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/social/AddFriendDialog.kt index 36323fa0..c9d494c3 100644 --- a/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/social/AddFriendDialog.kt +++ b/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/social/AddFriendDialog.kt @@ -375,8 +375,7 @@ class AddFriendDialog( enabled = !allFriendsSelected ) { Text( - text = context.translation["manager.dialogs.messaging_action.select_all_button"] - ?: "Select All", + text = context.translation["manager.dialogs.messaging_action.select_all_button"], color = if (allFriendsSelected) { Color.White.copy(alpha = 0.45f) } else { diff --git a/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/social/ManageScope.kt b/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/social/ManageScope.kt index ff8bc62b..a002d0d6 100644 --- a/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/social/ManageScope.kt +++ b/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/social/ManageScope.kt @@ -91,7 +91,7 @@ class ManageScope: Routes.Route() { title = translation.format("delete_scope_confirm_dialog_title", "scope" to context.translation["scopes.${scope.key}"]), text = "", icon = Icons.Rounded.DeleteForever, - confirmButtonText = translation["delete_button"] ?: "Delete", + confirmButtonText = translation["delete_button"], dismissButtonText = context.translation["button.cancel"], onDismiss = { deleteConfirmDialog = false }, onConfirm = { @@ -109,7 +109,7 @@ class ManageScope: Routes.Route() { .background(PurrfectPalette.backgroundGradient) ) { FloatingTopBar( - title = titleText ?: "Manage", + title = titleText ?: translation["manage_scope_title"], onBack = { routes.navController.popBackStack() }, actions = { IconButton(onClick = { deleteConfirmDialog = true }) { diff --git a/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/social/MessagingPreview.kt b/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/social/MessagingPreview.kt index 2004f7d4..a7c1b9e7 100644 --- a/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/social/MessagingPreview.kt +++ b/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/social/MessagingPreview.kt @@ -63,7 +63,7 @@ import me.eternal.purrfectsnap.ui.util.Dialog import me.eternal.purrfectsnap.ui.util.purrfectSwitchColors class MessagingPreview: Routes.Route() { - override val translation by lazy { context.translation.getCategory("manager.sections.social.messaging_preview.messaging_preview") } + override val translation by lazy { context.translation.getCategory("manager.sections.social.messaging_preview") } private lateinit var coroutineScope: CoroutineScope private lateinit var previewScrollState: LazyListState @@ -79,21 +79,6 @@ class MessagingPreview: Routes.Route() { else selectedMessages.add(messageId) } - private fun tr(key: String, fallback: String? = null): String { - fun normalizeCandidate(candidate: String?): String? { - if (candidate.isNullOrBlank()) return null - if (candidate == key) return null - if (candidate.endsWith(".$key")) return null - return candidate - } - - return normalizeCandidate(translation.getOrNull(key)) - ?: normalizeCandidate(context.translation.getOrNull("manager.sections.social.messaging_preview.$key")) - ?: normalizeCandidate(context.translation.getOrNull("manager.social.messaging_preview.$key")) - ?: fallback - ?: key - } - @Composable private fun ActionsSheetItem( title: String, @@ -338,20 +323,20 @@ class MessagingPreview: Routes.Route() { val senderDisplayName by rememberAsyncMutableState(null, keys = arrayOf(senderId, myUserId, scope.key, scopeId, friendDisplayName)) { when { - senderId == null -> "Unknown" - senderId == myUserId -> "You" + senderId == null -> translation["sender_unknown"] + senderId == myUserId -> translation["sender_you"] scope == SocialScope.FRIEND -> friendDisplayName ?: context.database.getFriendInfo(scopeId)?.displayName ?: context.database.getFriendInfo(scopeId)?.mutableUsername - ?: "Friend" + ?: translation["sender_friend"] else -> context.database.getFriendInfo(senderId)?.displayName ?: context.database.getFriendInfo(senderId)?.mutableUsername - ?: "Unknown" + ?: translation["sender_unknown"] } } val contentTypeLabel = remember(contentType) { - contentType?.let { contentTypeTranslation.getOrNull(it.name) ?: it.name } ?: "Unknown" + contentType?.let { contentTypeTranslation.getOrNull(it.name) ?: it.name } ?: translation["sender_unknown"] } val bodyText = remember(message.contentType) { messageReader.getString(2, 1)?.trim().orEmpty() } @@ -408,7 +393,7 @@ class MessagingPreview: Routes.Route() { horizontalAlignment = if (isMine) Alignment.End else Alignment.Start ) { Text( - text = senderDisplayName ?: "Unknown", + text = senderDisplayName ?: translation["sender_unknown"], color = Color.White.copy(alpha = 0.82f), fontSize = 12.sp, fontWeight = FontWeight.SemiBold, @@ -487,7 +472,7 @@ class MessagingPreview: Routes.Route() { .padding(40.dp), horizontalArrangement = Arrangement.Center ) { - Text(tr("no_message_hint", "No messages"), color = PurrfectPalette.textSecondary) + Text(translation["no_message_hint"], color = PurrfectPalette.textSecondary) } } Spacer(modifier = Modifier.height(20.dp)) @@ -564,7 +549,7 @@ class MessagingPreview: Routes.Route() { translation.format("processed_message_toast", "count" to processMessageCount.intValue.toString()) } ?: translation.getOrNull("processed_messages_toast")?.let { translation.format("processed_messages_toast", "count" to processMessageCount.intValue.toString()) - } ?: "Processed ${processMessageCount.intValue} messages" + } ?: translation.format("processed_messages_toast", "count" to processMessageCount.intValue.toString()) context.longToast(toastText) } } @@ -579,7 +564,7 @@ class MessagingPreview: Routes.Route() { context.longToast( translation.getOrNull("bridge_connection_error") ?: translation.getOrNull("bridge_connection_failed") - ?: "Failed to connect to bridge" + ?: translation["bridge_connection_error"] ) return } @@ -640,7 +625,7 @@ class MessagingPreview: Routes.Route() { ) { val processedText = translation.getOrNull("processed_messages_text")?.let { translation.format("processed_messages_text", "count" to processMessageCount.intValue.toString()) - } ?: "Processed ${processMessageCount.intValue}" + } ?: translation.format("processed_messages_text", "count" to processMessageCount.intValue.toString()) Text(processedText) if (activeTask?.hasFixedGoal() == true) { LinearProgressIndicator( @@ -679,7 +664,7 @@ class MessagingPreview: Routes.Route() { }.onFailure { context.log.error("Failed to fetch messages", it) context.shortToast( - translation.getOrNull("message_fetch_failed") ?: "Failed to fetch messages" + translation.getOrNull("message_fetch_failed") ?: translation["message_fetch_failed"] ) } } @@ -710,7 +695,7 @@ class MessagingPreview: Routes.Route() { fetchNewMessages() }.onFailure { context.longToast( - translation.getOrNull("bridge_init_failed") ?: "Failed to initialize messaging bridge" + translation.getOrNull("bridge_init_failed") ?: translation["bridge_init_failed"] ) context.log.error("Failed to initialize messaging bridge", it) } @@ -751,11 +736,11 @@ class MessagingPreview: Routes.Route() { .background(PurrfectPalette.backgroundGradient) ) { FloatingTopBar( - title = titleText ?: translation["title"] ?: "Preview", + title = titleText ?: translation["title"], subtitle = if (selectedMessages.isNotEmpty()) { "${selectedMessages.size} selected" } else { - tr("subtitle", "Hold to select") + translation["subtitle"] .substringBefore("•") .substringBefore("·") .substringBefore("|") @@ -798,7 +783,7 @@ class MessagingPreview: Routes.Route() { Text( translation.getOrNull("bridge_connection_error") ?: translation.getOrNull("bridge_connection_failed") - ?: "Failed to connect to bridge", + ?: translation["bridge_connection_error"], modifier = Modifier.padding(16.dp), color = Color.White ) @@ -831,7 +816,7 @@ class MessagingPreview: Routes.Route() { val selectionSubtitle = if (hasSelection) { "${selectedMessages.size} selected" } else { - "Choose message types" + translation["choose_message_types_subtitle"] } Column( @@ -862,7 +847,7 @@ class MessagingPreview: Routes.Route() { ) Spacer(Modifier.height(14.dp)) Text( - text = tr("actions_title", "Conversation Actions"), + text = translation["actions_title"], color = Color.White, fontWeight = FontWeight.ExtraBold, fontSize = 18.sp, @@ -886,31 +871,31 @@ class MessagingPreview: Routes.Route() { val deleteKey = if (hasSelection) "delete_selection_option" else "delete_all_option" ActionsSheetItem( - title = tr(saveKey, if (hasSelection) "Save Selection" else "Save All"), - subtitle = if (hasSelection) "Save selected messages" else "Save by content type", + title = translation[saveKey], + subtitle = if (hasSelection) translation["save_selected_messages_subtitle"] else translation["save_by_content_type_subtitle"], icon = Icons.Rounded.BookmarkAdded ) { launchMessagingTask(MessagingTaskType.SAVE) if (hasSelection) runCurrentTask() else selectConstraintsDialog = true } ActionsSheetItem( - title = tr(unsaveKey, if (hasSelection) "Unsave Selection" else "Unsave All"), - subtitle = if (hasSelection) "Unsave selected messages" else "Unsave by content type", + title = translation[unsaveKey], + subtitle = if (hasSelection) translation["unsave_selected_messages_subtitle"] else translation["unsave_by_content_type_subtitle"], icon = Icons.Rounded.BookmarkBorder ) { launchMessagingTask(MessagingTaskType.UNSAVE) if (hasSelection) runCurrentTask() else selectConstraintsDialog = true } ActionsSheetItem( - title = tr(markKey, if (hasSelection) "Mark selected as seen" else "Mark all as seen"), - subtitle = "Marks snaps as seen", + title = translation[markKey], + subtitle = translation["mark_as_seen_subtitle"], icon = Icons.Rounded.RemoveRedEye ) { if (messagingBridge == null) { context.longToast( translation.getOrNull("bridge_connection_error") ?: translation.getOrNull("bridge_connection_failed") - ?: "Failed to connect to bridge" + ?: translation["bridge_connection_error"] ) return@ActionsSheetItem } @@ -924,8 +909,8 @@ class MessagingPreview: Routes.Route() { runCurrentTask() } ActionsSheetItem( - title = tr(deleteKey, if (hasSelection) "Delete Selection" else "Delete All"), - subtitle = if (hasSelection) "Delete selected messages" else "Delete by content type", + title = translation[deleteKey], + subtitle = if (hasSelection) translation["delete_selected_messages_subtitle"] else translation["delete_by_content_type_subtitle"], icon = Icons.Rounded.DeleteForever, danger = true ) { @@ -933,7 +918,7 @@ class MessagingPreview: Routes.Route() { context.longToast( translation.getOrNull("bridge_connection_error") ?: translation.getOrNull("bridge_connection_failed") - ?: "Failed to connect to bridge" + ?: translation["bridge_connection_error"] ) return@ActionsSheetItem } diff --git a/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/social/SocialRootSection.kt b/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/social/SocialRootSection.kt index 169ec03e..874349e1 100644 --- a/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/social/SocialRootSection.kt +++ b/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/social/SocialRootSection.kt @@ -237,7 +237,7 @@ class SocialRootSection : Routes.Route() { } ) if (searchActive) { - val searchHint = context.translation["manager.dialogs.add_friend.search_hint"] ?: "Search" + val searchHint = context.translation["manager.dialogs.add_friend.search_hint"] val searchShape = RoundedCornerShape(18.dp) val searchBorder = Brush.linearGradient( listOf( @@ -520,7 +520,7 @@ class SocialRootSection : Routes.Route() { verticalArrangement = Arrangement.spacedBy(4.dp) ) { Text( - text = translation["manager.routes.social"] ?: "Social", + text = translation["manager.routes.social"], color = Color.White, fontWeight = FontWeight.ExtraBold, fontSize = 18.sp @@ -631,7 +631,7 @@ class SocialRootSection : Routes.Route() { fontSize = 15.sp ) Text( - text = translation["social_empty_hint"] ?: "Tap the + button to sync friends or groups.", + text = translation["social_empty_hint"], color = PurrfectPalette.textSecondary, fontSize = 12.sp ) diff --git a/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/tracker/FriendTrackerCatalog.kt b/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/tracker/FriendTrackerCatalog.kt index c15a78b4..d765474c 100644 --- a/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/tracker/FriendTrackerCatalog.kt +++ b/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/tracker/FriendTrackerCatalog.kt @@ -148,7 +148,7 @@ class FriendTrackerCatalog : Routes.Route() { contentColor = Color.White ) ) { - Text(translation["manage_repos_description"] ?: (context.translation["manager.routes.manage_friend_tracker_repos"] ?: "Manage repositories")) + Text(translation["manage_repos_description"] ?: context.translation["manager.routes.manage_friend_tracker_repos"]) } } ) @@ -176,7 +176,7 @@ class FriendTrackerCatalog : Routes.Route() { } } catch (e: Exception) { withContext(Dispatchers.Main) { - context.shortToast(translation.format("error", "message" to (e.localizedMessage ?: "Unknown"))) + context.shortToast(translation.format("error", "message" to (e.localizedMessage ?: context.translation["common.unknown"]))) } } } @@ -341,7 +341,7 @@ class FriendTrackerCatalog : Routes.Route() { .background(PurrfectPalette.backgroundGradient) ) { FloatingTopBar( - title = translation["title"] ?: (routeInfo.translatedKey?.value ?: "Catalog"), + title = translation["title"], onBack = { routes.navController.popBackStack() }, actions = { IconButton(onClick = { routes.manageFriendTrackerRepos.navigate() }) { diff --git a/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/tracker/FriendTrackerConfigExportScreen.kt b/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/tracker/FriendTrackerConfigExportScreen.kt index 37bfcbee..ac9693f0 100644 --- a/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/tracker/FriendTrackerConfigExportScreen.kt +++ b/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/tracker/FriendTrackerConfigExportScreen.kt @@ -115,7 +115,7 @@ class FriendTrackerConfigExportScreen : Routes.Route() { } } }.onFailure { - context.longToast(translation.format("export_failed_toast", "message" to (it.message ?: "Unknown"))) + context.longToast(translation.format("export_failed_toast", "message" to (it.message ?: context.translation["common.unknown"]))) } } }) { diff --git a/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/tracker/FriendTrackerConfigImportScreen.kt b/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/tracker/FriendTrackerConfigImportScreen.kt index fd52855e..5d8ecda7 100644 --- a/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/tracker/FriendTrackerConfigImportScreen.kt +++ b/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/tracker/FriendTrackerConfigImportScreen.kt @@ -78,7 +78,7 @@ class FriendTrackerConfigImportScreen : Routes.Route() { routes.onRuleImported?.invoke() routes.navController.popBackStack() }.onFailure { - context.longToast(translation.format("import_failed_toast", "message" to (it.message ?: "Unknown"))) + context.longToast(translation.format("import_failed_toast", "message" to (it.message ?: context.translation["common.unknown"]))) } }) { Text(translation["confirm_button"]) diff --git a/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/tracker/ManageFriendTrackerReposSection.kt b/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/tracker/ManageFriendTrackerReposSection.kt index 4b63380a..38e1710b 100644 --- a/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/tracker/ManageFriendTrackerReposSection.kt +++ b/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/tracker/ManageFriendTrackerReposSection.kt @@ -245,7 +245,7 @@ class ManageFriendTrackerReposSection: Routes.Route() { } }.onFailure { context.log.error("Failed to add repository", it) - context.shortToast(translation.format("add_repo_failed_toast", "message" to (it.message ?: "Unknown"))) + context.shortToast(translation.format("add_repo_failed_toast", "message" to (it.message ?: context.translation["common.unknown"]))) } loading = false } @@ -282,7 +282,7 @@ class ManageFriendTrackerReposSection: Routes.Route() { .background(PurrfectPalette.backgroundGradient) ) { FloatingTopBar( - title = routeInfo.translatedKey?.value ?: (translation["title"] ?: "Repositories"), + title = routeInfo.translatedKey?.value ?: translation["title"], onBack = { routes.navController.popBackStack() }, modifier = Modifier .zIndex(2f) diff --git a/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/tracker/TrackerConfigParser.kt b/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/tracker/TrackerConfigParser.kt index a3b70d5e..70b86d25 100644 --- a/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/tracker/TrackerConfigParser.kt +++ b/app/src/main/kotlin/me/eternal/purrfectsnap/ui/manager/pages/tracker/TrackerConfigParser.kt @@ -16,10 +16,14 @@ class TrackerConfigParser(private val context: Routes.Route) { fun parse(configJson: String): Map> { val featureMap = mutableMapOf>() val exportedData = context.context.gson.fromJson(configJson, ExportedTrackerData::class.java) + val authorLabel = context.translation["tracker_author_label"] + val enabledLabel = context.translation["tracker_enabled_label"] + val enabledValue = context.translation["tracker_enabled_value"] + val disabledValue = context.translation["tracker_disabled_value"] exportedData.rules.forEach { rule -> val features = mutableListOf() - features.add(ImportedFeature(rule.name, "Author", "author", rule.author ?: "Unknown", 0)) - features.add(ImportedFeature(rule.name, "Enabled", "enabled", rule.enabled, 0)) + features.add(ImportedFeature(rule.name, authorLabel, "author", rule.author ?: context.context.translation["common.unknown"], 0)) + features.add(ImportedFeature(rule.name, enabledLabel, "enabled", if (rule.enabled) enabledValue else disabledValue, 0)) rule.events?.forEach { event -> features.add(ImportedFeature(rule.name, context.context.translation["tracker_events.${event.eventType}"], event.eventType, event.actions.joinToString(", ") { context.context.translation["tracker_actions.${it.key}"] }, 1)) } @@ -30,7 +34,7 @@ class TrackerConfigParser(private val context: Routes.Route) { fun parseValue(featureKey: String, value: Any): Any { return when (value) { - is Boolean -> if (value) "Enabled" else "Disabled" + is Boolean -> if (value) context.translation["tracker_enabled_value"] else context.translation["tracker_disabled_value"] is JSONArray -> { val list = mutableListOf() for (i in 0 until value.length()) { diff --git a/app/src/main/kotlin/me/eternal/purrfectsnap/ui/util/AlertDialogs.kt b/app/src/main/kotlin/me/eternal/purrfectsnap/ui/util/AlertDialogs.kt index 7cc73704..8ebc7f80 100644 --- a/app/src/main/kotlin/me/eternal/purrfectsnap/ui/util/AlertDialogs.kt +++ b/app/src/main/kotlin/me/eternal/purrfectsnap/ui/util/AlertDialogs.kt @@ -499,7 +499,7 @@ class AlertDialogs( currentColor = null } }, - label = { Text(text = "Hex Color") }, + label = { Text(text = translation["dialogs.hex_color_label"]) }, modifier = Modifier .fillMaxWidth() .padding(10.dp), @@ -816,7 +816,7 @@ class AlertDialogs( color = Color.White ) Text( - text = "Search or tap on the map", + text = betterLocationTranslation["search_or_tap_map_hint"], fontSize = 12.sp, color = PurrfectPalette.textSecondary ) @@ -870,11 +870,11 @@ class AlertDialogs( search() } }, - placeholder = { Text(text = "Search location...") }, + placeholder = { Text(text = betterLocationTranslation["search_location_placeholder"]) }, leadingIcon = { Icon( imageVector = Icons.Filled.Search, - contentDescription = "Search", + contentDescription = betterLocationTranslation["search_icon_description"], tint = Color.White ) }, @@ -994,7 +994,7 @@ class AlertDialogs( ) Spacer(modifier = Modifier.width(12.dp)) Text( - text = "Searching...", + text = betterLocationTranslation["searching_label"], style = MaterialTheme.typography.bodyMedium, color = Color.White ) @@ -1142,7 +1142,7 @@ class AlertDialogs( .padding(horizontal = 6.dp), value = lat.value, onValueChange = { lat.value = it }, - label = { Text(text = "Latitude") }, + label = { Text(text = translation["latitude_dialog_hint"]) }, leadingIcon = { Icon(Icons.Filled.MyLocation, contentDescription = null) }, singleLine = true, shape = RoundedCornerShape(14.dp), @@ -1162,7 +1162,7 @@ class AlertDialogs( .padding(horizontal = 6.dp), value = lon.value, onValueChange = { lon.value = it }, - label = { Text(text = "Longitude") }, + label = { Text(text = translation["longitude_dialog_hint"]) }, leadingIcon = { Icon(Icons.Filled.Navigation, contentDescription = null) }, singleLine = true, shape = RoundedCornerShape(14.dp), diff --git a/common/src/main/assets/lang/en_US.json b/common/src/main/assets/lang/en_US.json index 093b1a7b..e7294424 100644 --- a/common/src/main/assets/lang/en_US.json +++ b/common/src/main/assets/lang/en_US.json @@ -28,7 +28,8 @@ "dialogs": { "select_language": "Select Language", "save_folder": "Choose where to save downloads", - "select_save_folder_button": "Select Folder" + "select_save_folder_button": "Select Folder", + "hex_color_label": "Hex Color" }, "install_mode": { "confirm_timeout": "I understand ({seconds}s)", @@ -196,7 +197,7 @@ }, "sections": { "home": { - "version_title": "v{versionName} \u00b7 by Eternal", + "version_title": "v{versionName} \u00b7 by ΞTΞRNAL", "update_title": "PurrfectSnap Update", "update_content": "Version {version} is available!", "update_button": "Download", @@ -246,7 +247,7 @@ "about_tagline": "An Xposed Module meant to enhance your Snapchat experience!", "about_lead_developers_title": "Lead Developers", "about_story_title": "Our Story", - "about_story": "PurrfectSnap was founded on 2nd of October, 2025, as a fork of SnapEnhance by IzTIzRNAL with a vision to provide users the quality Snapchat experience they deserve. This app was just meant to be a minor update in the SnapEnhance repository, but it soon became a separate app wherein the contributors kept adding features. Then the developer joined the team, and this app soon became a huge success. We received much love and support and gained 1K+ downloads in just two days! We thank all users and contributors; without your support, we wouldn't have reached this place. We would also like to convey our huge thanks to rhunk, the lead developer of SnapEnhance, as without him, this app wouldn't even exist. We are immensely grateful to him. Lastly, we would like to thank all our admins, notably: CLASSIC GENIUS, Harry, SUJI>L, Zain & scrodingerspet, who were right there with us from the very beginning. We would also like to thank all testers, notably Leo & Toxic, who tested and reported bugs continuously. We are immensely grateful for your contribution.", + "about_story": "PurrfectSnap was founded on 2nd of October, 2025, as a fork of SnapEnhance by ΞTΞRNAL with a vision to provide users the quality Snapchat experience they deserve. This app was just meant to be a minor update in the SnapEnhance repository, but it soon became a separate app wherein the contributors kept adding features. Then the developer joined the team, and this app soon became a huge success. We received much love and support and gained 1K+ downloads in just two days! We thank all users and contributors; without your support, we wouldn't have reached this place. We would also like to convey our huge thanks to rhunk, the lead developer of SnapEnhance, as without him, this app wouldn't even exist. We are immensely grateful to him. Lastly, we would like to thank all our admins, notably: CLASSIC GENIUS, Harry, Sujal, Zain & schrodingerspet, who were right there with us from the very beginning. We would also like to thank all testers, notably Leo & Toxic, who tested and reported bugs continuously. We are immensely grateful for your contribution.", "about_thanks_title": "With love, PurrfectSnap Team", "about_magic_toast": "Tap 5 times in this screen to see some magic 😉!", "github_button": "GitHub", @@ -254,6 +255,7 @@ }, "home_logs": { "no_logs_hint": "No logs available", + "refresh_hint": "Pull to refresh or trigger an action to see new entries.", "clear_logs_button": "Clear Logs", "export_logs_button": "Export Logs", "saving_logs_toast": "Saving logs, this may take a while ...", @@ -341,7 +343,7 @@ "remove_selected_tasks_confirm": "Remove {count} tasks?", "remove_all_tasks_confirm": "Remove all tasks?" }, - "features": { + "features": { "disabled": "Disabled", "export_option": "Export", "import_option": "Import", @@ -353,10 +355,11 @@ "saved_config_snackbar": "Config saved", "older_required": "This feature requires Snapchat v{version} or older to work correctly", "newer_required": "This feature requires Snapchat v{version} or newer to work correctly", - "search_button": "Search", - "clear_history": "Clear search history", - "subtitle": "Search and manage features" - }, + "search_button": "Search", + "search_results_count": "{count} messages", + "clear_history": "Clear search history", + "subtitle": "Search and manage features" + }, "bypass_status": { "active": "PurrAura Active", "inactive": "PurrAura Inactive" @@ -371,7 +374,9 @@ "blacklist_state_subtext": "Everyone except {count} friends/groups will be affected by this rule", "blacklist_state_button": "Select excluded friends/groups", "clear_list_button": "Clear friends/groups list", - "dialog_clear_confirmation_text": "Are you sure you want to clear the list?" + "dialog_clear_confirmation_text": "Are you sure you want to clear the list?", + "dialog_clear_confirm_button": "Clear", + "dialog_clear_cancel_button": "Cancel" }, "social": { "friends_tab": "Friends", @@ -387,6 +392,7 @@ "social_empty_hint": "Tap the + button to sync friends or groups." }, "manage_scope": { + "manage_scope_title": "Manage", "logged_stories_button": "Show Logged Stories", "e2ee_title": "End-to-End Encryption", "e2ee_subtitle": "Manage your shared key for this friend.", @@ -417,16 +423,27 @@ "bridge_init_failed": "Failed to initialize messaging bridge. Make sure Snapchat is running in the background", "message_fetch_failed": "Failed to fetch messages", "no_message_hint": "No message", + "sender_unknown": "Unknown", + "sender_you": "You", + "sender_friend": "Friend", "subtitle": "Hold to select", "actions_title": "Conversation Actions", + "choose_message_types_subtitle": "Choose message types", "save_selection_option": "Save Selection", "save_all_option": "Save All", + "save_selected_messages_subtitle": "Save selected messages", + "save_by_content_type_subtitle": "Save by content type", "unsave_selection_option": "Unsave Selection", "unsave_all_option": "Unsave All", + "unsave_selected_messages_subtitle": "Unsave selected messages", + "unsave_by_content_type_subtitle": "Unsave by content type", "mark_selection_as_seen_option": "Mark selected Snap as seen", "mark_all_as_seen_option": "Mark all Snaps as seen", + "mark_as_seen_subtitle": "Marks snaps as seen", "delete_selection_option": "Delete Selection", "delete_all_option": "Delete All", + "delete_selected_messages_subtitle": "Delete selected messages", + "delete_by_content_type_subtitle": "Delete by content type", "processed_message_toast": "Processed {count} messages", "processed_messages_toast": "Processed {count} messages", "processed_messages_text": "Processed {count}", @@ -459,6 +476,10 @@ "longitude_dialog_hint": "Longitude", "save_dialog_button": "Save", "choose_location_button": "Pick a Location", + "search_or_tap_map_hint": "Search or tap on the map", + "search_location_placeholder": "Search location...", + "search_icon_description": "Search", + "searching_label": "Searching...", "manual_coordinates_hint": "Fine-tune the coordinates manually.", "saved_coordinates_subtitle": "Manage your saved spoof locations", "teleport_to_friend_button": "Teleport to Friend", @@ -660,6 +681,10 @@ "save_button": "Save", "back_button_description": "Go back", "expand_button_description": "Expand or collapse category", + "tracker_author_label": "Author", + "tracker_enabled_label": "Enabled", + "tracker_enabled_value": "Enabled", + "tracker_disabled_value": "Disabled", "exported_toast": "Tracker configuration exported", "export_failed_toast": "Failed to export tracker: {message}" }, @@ -668,6 +693,10 @@ "confirm_button": "Import", "back_button_description": "Go back", "expand_button_description": "Expand or collapse category", + "tracker_author_label": "Author", + "tracker_enabled_label": "Enabled", + "tracker_enabled_value": "Enabled", + "tracker_disabled_value": "Disabled", "imported_toast": "Tracker imported", "import_failed_toast": "Failed to import tracker: {message}" }, @@ -3444,17 +3473,22 @@ }, "common": { "cancel": "Cancel", + "close": "Close", "add": "Add", "ok": "OK", "quit": "Quit", "done": "Done", "back": "Back", "unknown": "Unknown", + "unknown_error": "Unknown error", + "not_available": "N/A", "added": "Added", "no_friends_found": "No friends found", "exporting_memories": "Exporting memories... ({failed} failed)" }, "clear_friend_feed": "Clear Friend Feed", + "task_media_conversion_title": "Media conversion", + "task_call_recording_title": "Call Recording {author}", "select_date": "Select Date", "schedule_scheduled_for": "Scheduled for {name} in {time}", "schedule_sending_in": "Sending in {time}",