From ba1d61d8d958819106719fa4f596315310a2d5be Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 1 Mar 2026 20:44:43 +0000 Subject: [PATCH] feat: move hardcoded UI strings to strings.xml Replaces hardcoded string literals in composables with string resource references for proper i18n support. Adds 20 new strings to strings.xml. Files updated: - NewUserMetadataScreen: "Social proof" section title - NoteCompose: "Approve" community post button - Badge: " and N others" badge awardees text - Chess: "Decline"/"Accept" challenge buttons - InteractiveStory: "Restart" story button - Poll: "Submit" poll button - ChessGameScreen: "Back", "Relay Settings", "Loading game...", "Game Not Found", "This game may have ended...", "Game ID: ...", "Go Back" - ChessLobbyScreen: "Back", "Relay Settings", "New Game", "Dismiss", "Connected" - chess/NewChessGameButton: "New Chess Game" content description - home/NewChessGameButton: "New Chess Game" content description - UserSettingsScreen: "Remove " content description https://claude.ai/code/session_0151CDmy5k2pEWnxhRxet41h --- .../ui/actions/NewUserMetadataScreen.kt | 2 +- .../amethyst/ui/note/NoteCompose.kt | 2 +- .../amethyst/ui/note/types/Badge.kt | 2 +- .../amethyst/ui/note/types/Chess.kt | 6 ++++-- .../ui/note/types/InteractiveStory.kt | 4 +++- .../amethyst/ui/note/types/Poll.kt | 4 +++- .../screen/loggedIn/chess/ChessGameScreen.kt | 18 +++++++++-------- .../screen/loggedIn/chess/ChessLobbyScreen.kt | 11 +++++----- .../loggedIn/chess/NewChessGameButton.kt | 4 +++- .../loggedIn/home/NewChessGameButton.kt | 4 +++- .../loggedIn/settings/UserSettingsScreen.kt | 2 +- amethyst/src/main/res/values/strings.xml | 20 +++++++++++++++++++ 12 files changed, 56 insertions(+), 23 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataScreen.kt index 9603b9b11..33722468d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataScreen.kt @@ -291,7 +291,7 @@ fun NewUserMetadataScreen( // -- Social Proofs -- ExpandableSection( - title = "Social proof", + title = stringRes(R.string.social_proof), expanded = socialExpanded, ) { OutlinedTextField( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt index c2da8f66e..97dad11df 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt @@ -670,7 +670,7 @@ fun RenderApproveButton( accountViewModel.approveCommunityPost(post, community) }, ) { - Text("Approve") + Text(stringRes(R.string.approve)) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Badge.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Badge.kt index 639612b34..cf2156375 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Badge.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Badge.kt @@ -172,7 +172,7 @@ fun RenderBadgeAward( } if (awardees.size > 100) { - Text(" and ${awardees.size - 100} others", maxLines = 1) + Text(stringRes(R.string.badge_and_n_others, awardees.size - 100), maxLines = 1) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Chess.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Chess.kt index af7b3d472..7580565c3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Chess.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Chess.kt @@ -41,6 +41,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel +import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.chess.ChessChallenge import com.vitorpamplona.amethyst.commons.chess.ChessGameViewer import com.vitorpamplona.amethyst.model.Note @@ -48,6 +49,7 @@ import com.vitorpamplona.amethyst.ui.components.SensitivityWarning import com.vitorpamplona.amethyst.ui.navigation.navs.INav import com.vitorpamplona.amethyst.ui.navigation.routes.Route import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.screen.loggedIn.chess.ChessViewModelFactory import com.vitorpamplona.amethyst.ui.screen.loggedIn.chess.ChessViewModelNew import com.vitorpamplona.quartz.nip64Chess.ChessGameEvent @@ -178,7 +180,7 @@ fun RenderLiveChessChallenge( horizontalArrangement = Arrangement.End, ) { OutlinedButton(onClick = { /* TODO: Decline */ }) { - Text("Decline") + Text(stringRes(R.string.chess_decline)) } Spacer(modifier = Modifier.width(8.dp)) @@ -207,7 +209,7 @@ fun RenderLiveChessChallenge( nav.nav(Route.ChessGame(gameId)) }, ) { - Text("Accept") + Text(stringRes(R.string.chess_accept)) } } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/InteractiveStory.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/InteractiveStory.kt index 71e7ba8a8..8bd1c060e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/InteractiveStory.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/InteractiveStory.kt @@ -46,7 +46,9 @@ import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNo import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.ui.navigation.navs.INav import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote +import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.quartz.experimental.interactiveStories.InteractiveStoryBaseEvent import com.vitorpamplona.quartz.experimental.interactiveStories.InteractiveStoryReadingStateEvent import com.vitorpamplona.quartz.nip01Core.core.HexKey @@ -183,7 +185,7 @@ fun RenderInteractiveStory( OutlinedButton( onClick = onRestart, ) { - Text("Restart") + Text(stringRes(R.string.restart)) } } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Poll.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Poll.kt index e2bdc9642..6c26e2937 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Poll.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Poll.kt @@ -77,8 +77,10 @@ import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor import com.vitorpamplona.amethyst.ui.note.ClickableUserPicture import com.vitorpamplona.amethyst.ui.note.elements.DisplayUncitedHashtags import com.vitorpamplona.amethyst.ui.note.showCount +import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.BigPadding import com.vitorpamplona.amethyst.ui.theme.Size25dp import com.vitorpamplona.amethyst.ui.theme.SmallishBorder @@ -392,7 +394,7 @@ private fun ColumnScope.RenderMultiChoiceOptions( modifier = Modifier.align(Alignment.End), enabled = multichoice.isNotEmpty(), ) { - Text("Submit") + Text(stringRes(R.string.poll_submit)) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/ChessGameScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/ChessGameScreen.kt index c7c2c5ea4..7c9dc7d9d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/ChessGameScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/ChessGameScreen.kt @@ -68,8 +68,10 @@ import com.vitorpamplona.amethyst.commons.chess.ChessBroadcastBanner import com.vitorpamplona.amethyst.commons.chess.ChessBroadcastStatus import com.vitorpamplona.amethyst.commons.chess.ChessSyncBanner import com.vitorpamplona.amethyst.commons.chess.LiveChessGameScreen +import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.ui.navigation.navs.INav import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.Height4dpModifier import com.vitorpamplona.quartz.nip64Chess.ChessGameNameGenerator @@ -186,7 +188,7 @@ fun ChessGameScreen( IconButton(onClick = { nav.popBack() }) { Icon( imageVector = Icons.AutoMirrored.Filled.ArrowBack, - contentDescription = "Back", + contentDescription = stringRes(R.string.back), ) } }, @@ -194,7 +196,7 @@ fun ChessGameScreen( IconButton(onClick = { showRelaySettings = true }) { Icon( imageVector = Icons.Default.Settings, - contentDescription = "Relay Settings", + contentDescription = stringRes(R.string.relay_settings), ) } }, @@ -239,7 +241,7 @@ fun ChessGameScreen( Column(horizontalAlignment = Alignment.CenterHorizontally) { CircularProgressIndicator() Spacer(modifier = Modifier.height(16.dp)) - Text("Loading game...") + Text(stringRes(R.string.chess_loading_game)) } } } @@ -256,7 +258,7 @@ fun ChessGameScreen( verticalArrangement = Arrangement.Center, ) { Text( - text = "Game Not Found", + text = stringRes(R.string.chess_game_not_found), style = MaterialTheme.typography.headlineMedium, fontWeight = FontWeight.Bold, ) @@ -265,7 +267,7 @@ fun ChessGameScreen( // Show specific error if available Text( - text = error ?: "This game may have ended or is waiting for opponent.", + text = error ?: stringRes(R.string.chess_game_waiting), style = MaterialTheme.typography.bodyMedium, color = if (error != null) MaterialTheme.colorScheme.error else MaterialTheme.colorScheme.onSurfaceVariant, ) @@ -273,7 +275,7 @@ fun ChessGameScreen( Spacer(modifier = Modifier.height(8.dp)) Text( - text = "Game ID: ${gameId.take(16)}...", + text = stringRes(R.string.chess_game_id, gameId.take(16)), style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant, ) @@ -283,10 +285,10 @@ fun ChessGameScreen( Button(onClick = { nav.popBack() }) { Icon( imageVector = Icons.AutoMirrored.Filled.ArrowBack, - contentDescription = "Back", + contentDescription = stringRes(R.string.back), modifier = Modifier.padding(end = 8.dp), ) - Text("Go Back") + Text(stringRes(R.string.go_back)) } } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/ChessLobbyScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/ChessLobbyScreen.kt index fa7132a24..85445fc6e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/ChessLobbyScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/ChessLobbyScreen.kt @@ -82,6 +82,7 @@ import com.vitorpamplona.amethyst.commons.chess.PublicGame import com.vitorpamplona.amethyst.ui.navigation.navs.INav import com.vitorpamplona.amethyst.ui.navigation.routes.Route import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.quartz.nip64Chess.LiveChessGameState import kotlinx.coroutines.delay import kotlinx.coroutines.launch @@ -168,7 +169,7 @@ fun ChessLobbyScreen( IconButton(onClick = { nav.popBack() }) { Icon( imageVector = Icons.AutoMirrored.Filled.ArrowBack, - contentDescription = "Back", + contentDescription = stringRes(R.string.back), ) } }, @@ -176,7 +177,7 @@ fun ChessLobbyScreen( IconButton(onClick = { showRelaySettings = true }) { Icon( imageVector = Icons.Default.Settings, - contentDescription = "Relay Settings", + contentDescription = stringRes(R.string.relay_settings), ) } }, @@ -186,7 +187,7 @@ fun ChessLobbyScreen( FloatingActionButton( onClick = { showNewGameDialog = true }, ) { - Icon(Icons.Default.Add, contentDescription = "New Game") + Icon(Icons.Default.Add, contentDescription = stringRes(R.string.chess_new_game)) } }, ) { paddingValues -> @@ -238,7 +239,7 @@ fun ChessLobbyScreen( ) { Text(errorMsg, color = MaterialTheme.colorScheme.onErrorContainer) OutlinedButton(onClick = { chessViewModel.clearError() }) { - Text("Dismiss") + Text(stringRes(R.string.dismiss)) } } } @@ -730,7 +731,7 @@ private fun RelayRow( ) { Icon( imageVector = Icons.Default.CheckCircle, - contentDescription = "Connected", + contentDescription = stringRes(R.string.connected), tint = if (isPreferred) { MaterialTheme.colorScheme.tertiary diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/NewChessGameButton.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/NewChessGameButton.kt index c0baa2135..7281899c0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/NewChessGameButton.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/NewChessGameButton.kt @@ -28,6 +28,8 @@ import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.graphics.Color +import com.vitorpamplona.amethyst.R +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.Size26Modifier import com.vitorpamplona.amethyst.ui.theme.Size55Modifier @@ -45,7 +47,7 @@ fun NewChessGameButton(onClick: () -> Unit) { ) { Icon( imageVector = Icons.Default.Add, - contentDescription = "New Chess Game", + contentDescription = stringRes(R.string.new_chess_game), modifier = Size26Modifier, tint = Color.White, ) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/NewChessGameButton.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/NewChessGameButton.kt index ca4bbefb7..ef84acdb3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/NewChessGameButton.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/NewChessGameButton.kt @@ -25,6 +25,8 @@ import androidx.compose.material.icons.filled.Add import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.Icon import androidx.compose.runtime.Composable +import com.vitorpamplona.amethyst.R +import com.vitorpamplona.amethyst.ui.stringRes import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -57,7 +59,7 @@ fun NewChessGameButton( ) { Icon( imageVector = Icons.Default.Add, - contentDescription = "New Chess Game", + contentDescription = stringRes(R.string.new_chess_game), ) } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/UserSettingsScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/UserSettingsScreen.kt index ecbece34f..79c685f82 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/UserSettingsScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/UserSettingsScreen.kt @@ -131,7 +131,7 @@ fun DontTranslateFromSetting(accountViewModel: AccountViewModel) { trailingIcon = { Icon( imageVector = Icons.Default.Close, - contentDescription = "Remove $languageCode", + contentDescription = stringRes(R.string.remove_language, languageCode), tint = Color.Red, modifier = Modifier.size(16.dp), ) diff --git a/amethyst/src/main/res/values/strings.xml b/amethyst/src/main/res/values/strings.xml index cda62cff9..4421db8ef 100644 --- a/amethyst/src/main/res/values/strings.xml +++ b/amethyst/src/main/res/values/strings.xml @@ -1525,4 +1525,24 @@ Confirm Next Add poll option button + + Back + Go Back + Dismiss + Approve + Connected + Relay Settings + Social proof + Submit + Restart + Accept + Decline + New Game + New Chess Game + Loading game\u2026 + Game Not Found + This game may have ended or is waiting for opponent. + Game ID: %1$s\u2026 + and %1$d others + Remove %1$s