From 6e9e580b3f021cd28526d7f7d3fd846f93d31840 Mon Sep 17 00:00:00 2001 From: benya Date: Wed, 11 Mar 2026 06:41:23 +0300 Subject: [PATCH] Localize chat day labels and gif errors --- .../messenger/ui/chat/ChatScreen.kt | 52 +++++++++++++------ .../app/src/main/res/values-ru/strings.xml | 8 +++ android/app/src/main/res/values/strings.xml | 8 +++ 3 files changed, 53 insertions(+), 15 deletions(-) diff --git a/android/app/src/main/java/ru/daemonlord/messenger/ui/chat/ChatScreen.kt b/android/app/src/main/java/ru/daemonlord/messenger/ui/chat/ChatScreen.kt index 4a898c0..bdf0cb3 100644 --- a/android/app/src/main/java/ru/daemonlord/messenger/ui/chat/ChatScreen.kt +++ b/android/app/src/main/java/ru/daemonlord/messenger/ui/chat/ChatScreen.kt @@ -382,7 +382,7 @@ fun ChatScreen( val isPrivateChat = state.chatType.equals("private", ignoreCase = true) val canShowMembersTab = state.chatType.equals("group", ignoreCase = true) || (state.chatType.equals("channel", ignoreCase = true) && state.canManageMembers) - val timelineItems = remember(state.messages) { buildChatTimelineItems(state.messages) } + val timelineItems = remember(state.messages, context) { buildChatTimelineItems(state.messages, context) } val senderNameByUserId = remember(state.messages, state.chatMembers) { val fromMembers = state.chatMembers.associate { member -> val resolved = member.name.ifBlank { @@ -442,7 +442,7 @@ fun ChatScreen( val chatInfoSheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) val isTabletLayout = LocalConfiguration.current.screenWidthDp >= 840 val adaptiveHorizontalPadding = if (isTabletLayout) 72.dp else 0.dp - val chatInfoEntries = remember(state.messages) { buildChatInfoEntries(state.messages) } + val chatInfoEntries = remember(state.messages, context) { buildChatInfoEntries(state.messages, context) } val giphyApiKey = remember { BuildConfig.GIPHY_API_KEY.trim() } val firstUnreadIncomingMessageId = remember(state.messages, state.chatUnreadCount) { val unread = state.chatUnreadCount.coerceAtLeast(0) @@ -554,7 +554,7 @@ fun ChatScreen( } if (giphyApiKey.isBlank()) { giphySearchItems = emptyList() - giphyErrorMessage = "Set GIPHY_API_KEY in local.properties" + giphyErrorMessage = context.getString(R.string.chat_error_giphy_api_key_missing) isGiphyLoading = false return@LaunchedEffect } @@ -567,7 +567,11 @@ fun ChatScreen( limit = 24, ) giphySearchItems = found - giphyErrorMessage = if (found.isEmpty()) "No GIFs found" else null + giphyErrorMessage = if (found.isEmpty()) { + context.getString(R.string.chat_error_no_gifs_found) + } else { + null + } isGiphyLoading = false } LaunchedEffect(listState, timelineItems) { @@ -2193,6 +2197,8 @@ private fun MessageBubble( ?.takeIf { it.isNotBlank() } ?: message.senderUsername?.takeIf { it.isNotBlank() }?.let { "@$it" } ?: senderNameByUserId[message.senderId] + val unknownUserText = stringResource(id = R.string.chat_unknown_user) + val mediaPlaceholder = stringResource(id = R.string.chat_media_placeholder) val legacyTextUrl = message.text?.trim()?.takeIf { it.startsWith("http", ignoreCase = true) } val hasLegacyStickerImage = message.attachments.isEmpty() && message.type.equals("image", ignoreCase = true) && @@ -2264,7 +2270,11 @@ private fun MessageBubble( if (message.forwardedFromMessageId != null || !message.forwardedFromDisplayName.isNullOrBlank()) { Text( - text = "Forwarded from ${message.forwardedFromDisplayName?.takeIf { it.isNotBlank() } ?: "#${message.forwardedFromMessageId ?: "?"}"}", + text = stringResource( + id = R.string.chat_forwarded_from, + message.forwardedFromDisplayName?.takeIf { it.isNotBlank() } + ?: "#${message.forwardedFromMessageId ?: "?"}", + ), style = MaterialTheme.typography.labelSmall, color = secondaryTextColor, ) @@ -2287,8 +2297,8 @@ private fun MessageBubble( } val replyAuthor = replyAuthorFromPreview ?: replyAuthorByMessageId[message.replyToMessageId] - ?: "Unknown user" - val replySnippet = message.replyPreviewText?.takeIf { it.isNotBlank() } ?: "[media]" + ?: unknownUserText + val replySnippet = message.replyPreviewText?.takeIf { it.isNotBlank() } ?: mediaPlaceholder Row( modifier = Modifier .fillMaxWidth() @@ -2761,7 +2771,10 @@ private val defaultStickerItems = listOf( RemotePickerItem("Sticker 6", "https://raw.githubusercontent.com/twitter/twemoji/master/assets/72x72/1f602.png", "sticker_lol"), ) -private fun buildChatTimelineItems(messages: List): List { +private fun buildChatTimelineItems( + messages: List, + context: Context, +): List { if (messages.isEmpty()) return emptyList() val items = mutableListOf() var previousDate: LocalDate? = null @@ -2773,7 +2786,7 @@ private fun buildChatTimelineItems(messages: List): List "Сегодня" - date == today.minusDays(1) -> "Вчера" + date == today -> context.getString(R.string.chat_day_today) + date == today.minusDays(1) -> context.getString(R.string.chat_day_yesterday) else -> date.format(daySeparatorFormatter) } } @@ -2914,7 +2930,10 @@ private fun VoiceRecordingStatusRow( verticalAlignment = Alignment.CenterVertically, ) { Text( - text = "Voice ${formatDuration(durationMs.toInt())}", + text = stringResource( + id = R.string.chat_voice_recording_duration, + formatDuration(durationMs.toInt()), + ), style = MaterialTheme.typography.labelMedium, fontWeight = FontWeight.SemiBold, ) @@ -4014,7 +4033,10 @@ private fun ChatMembersTabContent( } } -private fun buildChatInfoEntries(messages: List): List { +private fun buildChatInfoEntries( + messages: List, + context: Context, +): List { val entries = mutableListOf() messages .sortedByDescending { it.id } @@ -4063,7 +4085,7 @@ private fun buildChatInfoEntries(messages: List): ListПроведите вверх, чтобы закрепить, и влево, чтобы отменить Запись закреплена Чат #%1$d + Сегодня + Вчера + Голос %1$s + Неизвестный пользователь + [медиа] + Переслано от %1$s + Укажите GIPHY_API_KEY в local.properties + GIF не найдены Пользователь АККАУНТЫ diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml index f9f5fd0..0da8c0a 100644 --- a/android/app/src/main/res/values/strings.xml +++ b/android/app/src/main/res/values/strings.xml @@ -130,6 +130,14 @@ Slide up to lock, slide left to cancel Recording locked Chat #%1$d + Today + Yesterday + Voice %1$s + Unknown user + [media] + Forwarded from %1$s + Set GIPHY_API_KEY in local.properties + No GIFs found User ACCOUNTS