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 <language>" content description

https://claude.ai/code/session_0151CDmy5k2pEWnxhRxet41h
This commit is contained in:
Claude
2026-03-01 20:44:43 +00:00
parent 16088be597
commit ba1d61d8d9
12 changed files with 56 additions and 23 deletions
@@ -291,7 +291,7 @@ fun NewUserMetadataScreen(
// -- Social Proofs --
ExpandableSection(
title = "Social proof",
title = stringRes(R.string.social_proof),
expanded = socialExpanded,
) {
OutlinedTextField(
@@ -670,7 +670,7 @@ fun RenderApproveButton(
accountViewModel.approveCommunityPost(post, community)
},
) {
Text("Approve")
Text(stringRes(R.string.approve))
}
}
@@ -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)
}
}
@@ -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))
}
}
}
@@ -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))
}
}
}
@@ -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))
}
}
@@ -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))
}
}
}
@@ -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
@@ -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,
)
@@ -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),
)
}
@@ -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),
)
+20
View File
@@ -1525,4 +1525,24 @@
<string name="confirm">Confirm</string>
<string name="next">Next</string>
<string name="add_poll_option_button">Add poll option button</string>
<string name="back">Back</string>
<string name="go_back">Go Back</string>
<string name="dismiss">Dismiss</string>
<string name="approve">Approve</string>
<string name="connected">Connected</string>
<string name="relay_settings">Relay Settings</string>
<string name="social_proof">Social proof</string>
<string name="poll_submit">Submit</string>
<string name="restart">Restart</string>
<string name="chess_accept">Accept</string>
<string name="chess_decline">Decline</string>
<string name="chess_new_game">New Game</string>
<string name="new_chess_game">New Chess Game</string>
<string name="chess_loading_game">Loading game\u2026</string>
<string name="chess_game_not_found">Game Not Found</string>
<string name="chess_game_waiting">This game may have ended or is waiting for opponent.</string>
<string name="chess_game_id">Game ID: %1$s\u2026</string>
<string name="badge_and_n_others"> and %1$d others</string>
<string name="remove_language">Remove %1$s</string>
</resources>