fix: add support for more keys for translations
This commit is contained in:
@@ -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
|
||||
)
|
||||
|
||||
@@ -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()
|
||||
)
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -232,7 +232,7 @@ class ConfigImportConfirmationScreen : Routes.Route() {
|
||||
routes.configJsonForImport?.let { parser.parse(it) } ?: emptyMap()
|
||||
}
|
||||
val expandedState = remember { mutableStateMapOf<String, Boolean>() }
|
||||
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"])
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 }) {
|
||||
|
||||
@@ -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<String?>(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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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() }) {
|
||||
|
||||
@@ -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"])))
|
||||
}
|
||||
}
|
||||
}) {
|
||||
|
||||
@@ -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"])
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -16,10 +16,14 @@ class TrackerConfigParser(private val context: Routes.Route) {
|
||||
fun parse(configJson: String): Map<String, List<ImportedFeature>> {
|
||||
val featureMap = mutableMapOf<String, MutableList<ImportedFeature>>()
|
||||
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<ImportedFeature>()
|
||||
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<String>()
|
||||
for (i in 0 until value.length()) {
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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 <RSR/> 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 <RSR/> 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}",
|
||||
|
||||
Reference in New Issue
Block a user