From f88d9a2a36c6de53cd9e68c5688db79a77bf1977 Mon Sep 17 00:00:00 2001 From: benya Date: Wed, 11 Mar 2026 20:52:27 +0300 Subject: [PATCH] Localize chat list management messages --- .../messenger/ui/chats/ChatListViewModel.kt | 88 ++++++++++++------- .../app/src/main/res/values-ru/strings.xml | 28 ++++++ android/app/src/main/res/values/strings.xml | 28 ++++++ 3 files changed, 114 insertions(+), 30 deletions(-) diff --git a/android/app/src/main/java/ru/daemonlord/messenger/ui/chats/ChatListViewModel.kt b/android/app/src/main/java/ru/daemonlord/messenger/ui/chats/ChatListViewModel.kt index 3e0b526..48352fe 100644 --- a/android/app/src/main/java/ru/daemonlord/messenger/ui/chats/ChatListViewModel.kt +++ b/android/app/src/main/java/ru/daemonlord/messenger/ui/chats/ChatListViewModel.kt @@ -1,8 +1,10 @@ package ru.daemonlord.messenger.ui.chats +import android.content.Context import androidx.appcompat.app.AppCompatDelegate import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow @@ -28,6 +30,7 @@ import ru.daemonlord.messenger.domain.realtime.usecase.HandleRealtimeEventsUseCa import ru.daemonlord.messenger.domain.settings.model.AppThemeMode import ru.daemonlord.messenger.domain.settings.repository.ThemeRepository import ru.daemonlord.messenger.domain.search.repository.SearchRepository +import ru.daemonlord.messenger.R import javax.inject.Inject @HiltViewModel @@ -42,6 +45,7 @@ class ChatListViewModel @Inject constructor( private val chatSearchRepository: ChatSearchRepository, private val searchRepository: SearchRepository, private val themeRepository: ThemeRepository, + @ApplicationContext private val context: Context, ) : ViewModel() { private val selectedTab = MutableStateFlow(ChatTab.ALL) @@ -232,7 +236,7 @@ class ChatListViewModel @Inject constructor( handle = null, description = null, memberIds = memberIds, - successMessage = "Group created.", + successMessageResId = R.string.chat_list_info_group_created, ) } @@ -244,7 +248,7 @@ class ChatListViewModel @Inject constructor( handle = handle, description = description, memberIds = emptyList(), - successMessage = "Channel created.", + successMessageResId = R.string.chat_list_info_channel_created, ) } @@ -254,7 +258,7 @@ class ChatListViewModel @Inject constructor( is AppResult.Success -> { _uiState.update { it.copy( - managementMessage = "Joined chat.", + managementMessage = context.getString(R.string.chat_list_info_joined_chat), pendingOpenChatId = result.data.id, ) } @@ -269,7 +273,7 @@ class ChatListViewModel @Inject constructor( viewModelScope.launch { when (val result = chatRepository.leaveChat(chatId = chatId)) { is AppResult.Success -> { - _uiState.update { it.copy(managementMessage = "Left chat.") } + _uiState.update { it.copy(managementMessage = context.getString(R.string.chat_list_info_left_chat)) } refreshCurrentTab(forceRefresh = true) } is AppResult.Error -> _uiState.update { it.copy(errorMessage = result.reason.toUiMessage()) } @@ -281,7 +285,7 @@ class ChatListViewModel @Inject constructor( viewModelScope.launch { when (val result = chatRepository.archiveChat(chatId = chatId)) { is AppResult.Success -> { - _uiState.update { it.copy(managementMessage = "Чат архивирован.") } + _uiState.update { it.copy(managementMessage = context.getString(R.string.chat_list_info_archived)) } refreshCurrentTab(forceRefresh = true) } is AppResult.Error -> _uiState.update { it.copy(errorMessage = result.reason.toUiMessage()) } @@ -293,7 +297,7 @@ class ChatListViewModel @Inject constructor( viewModelScope.launch { when (val result = chatRepository.unarchiveChat(chatId = chatId)) { is AppResult.Success -> { - _uiState.update { it.copy(managementMessage = "Чат возвращен из архива.") } + _uiState.update { it.copy(managementMessage = context.getString(R.string.chat_list_info_unarchived)) } refreshCurrentTab(forceRefresh = true) } is AppResult.Error -> _uiState.update { it.copy(errorMessage = result.reason.toUiMessage()) } @@ -304,7 +308,7 @@ class ChatListViewModel @Inject constructor( fun pinChat(chatId: Long) { viewModelScope.launch { when (val result = chatRepository.pinChat(chatId = chatId)) { - is AppResult.Success -> _uiState.update { it.copy(managementMessage = "Чат закреплен.") } + is AppResult.Success -> _uiState.update { it.copy(managementMessage = context.getString(R.string.chat_list_info_pinned)) } is AppResult.Error -> _uiState.update { it.copy(errorMessage = result.reason.toUiMessage()) } } } @@ -313,7 +317,7 @@ class ChatListViewModel @Inject constructor( fun unpinChat(chatId: Long) { viewModelScope.launch { when (val result = chatRepository.unpinChat(chatId = chatId)) { - is AppResult.Success -> _uiState.update { it.copy(managementMessage = "Чат откреплен.") } + is AppResult.Success -> _uiState.update { it.copy(managementMessage = context.getString(R.string.chat_list_info_unpinned)) } is AppResult.Error -> _uiState.update { it.copy(errorMessage = result.reason.toUiMessage()) } } } @@ -322,7 +326,7 @@ class ChatListViewModel @Inject constructor( fun clearChat(chatId: Long) { viewModelScope.launch { when (val result = chatRepository.clearChat(chatId = chatId)) { - is AppResult.Success -> _uiState.update { it.copy(managementMessage = "История чата очищена.") } + is AppResult.Success -> _uiState.update { it.copy(managementMessage = context.getString(R.string.chat_list_info_history_cleared)) } is AppResult.Error -> _uiState.update { it.copy(errorMessage = result.reason.toUiMessage()) } } } @@ -331,12 +335,12 @@ class ChatListViewModel @Inject constructor( fun updateChatTitle(chatId: Long, title: String) { val normalized = title.trim() if (normalized.isBlank()) { - _uiState.update { it.copy(errorMessage = "Title is required.") } + _uiState.update { it.copy(errorMessage = context.getString(R.string.chat_list_error_title_required)) } return } viewModelScope.launch { when (val result = chatRepository.updateChatTitle(chatId = chatId, title = normalized)) { - is AppResult.Success -> _uiState.update { it.copy(managementMessage = "Title updated.") } + is AppResult.Success -> _uiState.update { it.copy(managementMessage = context.getString(R.string.chat_list_info_title_updated)) } is AppResult.Error -> _uiState.update { it.copy(errorMessage = result.reason.toUiMessage()) } } } @@ -346,7 +350,7 @@ class ChatListViewModel @Inject constructor( val normalizedTitle = title?.trim()?.ifBlank { null } val normalizedDescription = description?.trim()?.ifBlank { null } if (normalizedTitle == null && normalizedDescription == null) { - _uiState.update { it.copy(errorMessage = "Provide title or description.") } + _uiState.update { it.copy(errorMessage = context.getString(R.string.chat_list_error_title_or_description_required)) } return } viewModelScope.launch { @@ -358,7 +362,7 @@ class ChatListViewModel @Inject constructor( avatarUrl = null, ) ) { - is AppResult.Success -> _uiState.update { it.copy(managementMessage = "Profile updated.") } + is AppResult.Success -> _uiState.update { it.copy(managementMessage = context.getString(R.string.chat_list_info_profile_updated)) } is AppResult.Error -> _uiState.update { it.copy(errorMessage = result.reason.toUiMessage()) } } } @@ -367,7 +371,7 @@ class ChatListViewModel @Inject constructor( fun deleteChatForMe(chatId: Long) { viewModelScope.launch { when (val result = chatRepository.removeChat(chatId = chatId, forAll = false)) { - is AppResult.Success -> _uiState.update { it.copy(managementMessage = "Чат удален.") } + is AppResult.Success -> _uiState.update { it.copy(managementMessage = context.getString(R.string.chat_list_info_deleted_for_me)) } is AppResult.Error -> _uiState.update { it.copy(errorMessage = result.reason.toUiMessage()) } } } @@ -376,7 +380,7 @@ class ChatListViewModel @Inject constructor( fun deleteChatForAll(chatId: Long) { viewModelScope.launch { when (val result = chatRepository.removeChat(chatId = chatId, forAll = true)) { - is AppResult.Success -> _uiState.update { it.copy(managementMessage = "Чат удален для всех.") } + is AppResult.Success -> _uiState.update { it.copy(managementMessage = context.getString(R.string.chat_list_info_deleted_for_all)) } is AppResult.Error -> _uiState.update { it.copy(errorMessage = result.reason.toUiMessage()) } } } @@ -389,7 +393,11 @@ class ChatListViewModel @Inject constructor( when (val updated = chatRepository.updateChatNotifications(chatId = chatId, muted = !current.data.muted)) { is AppResult.Success -> _uiState.update { it.copy( - managementMessage = if (updated.data.muted) "Уведомления выключены." else "Уведомления включены.", + managementMessage = if (updated.data.muted) { + context.getString(R.string.chat_list_info_notifications_disabled) + } else { + context.getString(R.string.chat_list_info_notifications_enabled) + }, ) } is AppResult.Error -> _uiState.update { it.copy(errorMessage = updated.reason.toUiMessage()) } @@ -404,7 +412,12 @@ class ChatListViewModel @Inject constructor( viewModelScope.launch { when (val result = chatRepository.createInviteLink(chatId = chatId)) { is AppResult.Success -> _uiState.update { - it.copy(managementMessage = "Invite: ${result.data.inviteUrl}") + it.copy( + managementMessage = context.getString( + R.string.chat_list_info_invite_created, + result.data.inviteUrl, + ), + ) } is AppResult.Error -> _uiState.update { it.copy(errorMessage = result.reason.toUiMessage()) } } @@ -415,7 +428,14 @@ class ChatListViewModel @Inject constructor( viewModelScope.launch { when (val result = chatRepository.addMember(chatId = chatId, userId = userId)) { is AppResult.Success -> { - _uiState.update { it.copy(managementMessage = "Added ${result.data.name}") } + _uiState.update { + it.copy( + managementMessage = context.getString( + R.string.chat_list_info_member_added, + result.data.name, + ), + ) + } loadMembersAndBans(chatId) } is AppResult.Error -> _uiState.update { it.copy(errorMessage = result.reason.toUiMessage()) } @@ -427,7 +447,15 @@ class ChatListViewModel @Inject constructor( viewModelScope.launch { when (val result = chatRepository.updateMemberRole(chatId = chatId, userId = userId, role = role)) { is AppResult.Success -> { - _uiState.update { it.copy(managementMessage = "Role updated: ${result.data.name} -> ${result.data.role}") } + _uiState.update { + it.copy( + managementMessage = context.getString( + R.string.chat_list_info_member_role_updated, + result.data.name, + result.data.role, + ), + ) + } loadMembersAndBans(chatId) } is AppResult.Error -> _uiState.update { it.copy(errorMessage = result.reason.toUiMessage()) } @@ -439,7 +467,7 @@ class ChatListViewModel @Inject constructor( viewModelScope.launch { when (val result = chatRepository.removeMember(chatId = chatId, userId = userId)) { is AppResult.Success -> { - _uiState.update { it.copy(managementMessage = "Member removed.") } + _uiState.update { it.copy(managementMessage = context.getString(R.string.chat_list_info_member_removed)) } loadMembersAndBans(chatId) } is AppResult.Error -> _uiState.update { it.copy(errorMessage = result.reason.toUiMessage()) } @@ -451,7 +479,7 @@ class ChatListViewModel @Inject constructor( viewModelScope.launch { when (val result = chatRepository.banMember(chatId = chatId, userId = userId)) { is AppResult.Success -> { - _uiState.update { it.copy(managementMessage = "Member banned.") } + _uiState.update { it.copy(managementMessage = context.getString(R.string.chat_list_info_member_banned)) } loadMembersAndBans(chatId) } is AppResult.Error -> _uiState.update { it.copy(errorMessage = result.reason.toUiMessage()) } @@ -463,7 +491,7 @@ class ChatListViewModel @Inject constructor( viewModelScope.launch { when (val result = chatRepository.unbanMember(chatId = chatId, userId = userId)) { is AppResult.Success -> { - _uiState.update { it.copy(managementMessage = "Member unbanned.") } + _uiState.update { it.copy(managementMessage = context.getString(R.string.chat_list_info_member_unbanned)) } loadMembersAndBans(chatId) } is AppResult.Error -> _uiState.update { it.copy(errorMessage = result.reason.toUiMessage()) } @@ -553,11 +581,11 @@ class ChatListViewModel @Inject constructor( handle: String?, description: String?, memberIds: List, - successMessage: String, + successMessageResId: Int, ) { val normalizedTitle = title.trim() if (normalizedTitle.isBlank()) { - _uiState.update { it.copy(errorMessage = "Title is required.") } + _uiState.update { it.copy(errorMessage = context.getString(R.string.chat_list_error_title_required)) } return } viewModelScope.launch { @@ -574,7 +602,7 @@ class ChatListViewModel @Inject constructor( is AppResult.Success -> { _uiState.update { it.copy( - managementMessage = successMessage, + managementMessage = context.getString(successMessageResId), pendingOpenChatId = result.data.id, ) } @@ -646,11 +674,11 @@ class ChatListViewModel @Inject constructor( private fun AppError.toUiMessage(): String { return when (this) { - AppError.Network -> "Network error while syncing chats." - AppError.Unauthorized -> "Session expired. Please log in again." - AppError.InvalidCredentials -> "Authorization failed." - is AppError.Server -> "Server error while loading chats." - is AppError.Unknown -> "Unknown error while loading chats." + AppError.Network -> context.getString(R.string.chat_list_error_network_sync) + AppError.Unauthorized -> context.getString(R.string.chat_list_error_session_expired) + AppError.InvalidCredentials -> context.getString(R.string.chat_list_error_authorization_failed) + is AppError.Server -> context.getString(R.string.chat_list_error_server_loading) + is AppError.Unknown -> context.getString(R.string.chat_list_error_unknown_loading) } } diff --git a/android/app/src/main/res/values-ru/strings.xml b/android/app/src/main/res/values-ru/strings.xml index dad3a59..8610689 100644 --- a/android/app/src/main/res/values-ru/strings.xml +++ b/android/app/src/main/res/values-ru/strings.xml @@ -38,6 +38,34 @@ Ночной режим Создать группу Избранное + Группа создана. + Канал создан. + Вы вступили в чат. + Вы вышли из чата. + Чат архивирован. + Чат возвращен из архива. + Чат закреплен. + Чат откреплен. + История чата очищена. + Название обновлено. + Профиль обновлен. + Чат удален. + Чат удален для всех. + Уведомления выключены. + Уведомления включены. + Приглашение: %1$s + Добавлен %1$s + Роль обновлена: %1$s -> %2$s + Участник удален. + Участник заблокирован. + Участник разблокирован. + Требуется название. + Укажите название или описание. + Ошибка сети при синхронизации чатов. + Сессия истекла. Войдите снова. + Ошибка авторизации. + Ошибка сервера при загрузке чатов. + Неизвестная ошибка при загрузке чатов. Включен дневной режим. Включен ночной режим. diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml index ada95fb..ec6a274 100644 --- a/android/app/src/main/res/values/strings.xml +++ b/android/app/src/main/res/values/strings.xml @@ -19,6 +19,34 @@ Night mode Create group Saved + Group created. + Channel created. + Joined chat. + Left chat. + Chat archived. + Chat restored from archive. + Chat pinned. + Chat unpinned. + Chat history cleared. + Title updated. + Profile updated. + Chat deleted. + Chat deleted for everyone. + Notifications disabled. + Notifications enabled. + Invite: %1$s + Added %1$s + Role updated: %1$s -> %2$s + Member removed. + Member banned. + Member unbanned. + Title is required. + Provide title or description. + Network error while syncing chats. + Session expired. Please log in again. + Authorization failed. + Server error while loading chats. + Unknown error while loading chats. Day mode enabled. Night mode enabled. No chats found