@@ -50,10 +50,12 @@ import androidx.compose.ui.Modifier
5050import androidx.compose.ui.platform.LocalHapticFeedback
5151import androidx.compose.ui.text.style.TextOverflow
5252import androidx.compose.ui.unit.dp
53+import androidx.compose.ui.res.stringResource
5354import androidx.lifecycle.compose.collectAsStateWithLifecycle
5455import androidx.lifecycle.viewmodel.compose.viewModel
5556import soy.iko.opencode.data.model.Session
5657import soy.iko.opencode.di.AppContainer
58+import soy.iko.opencode.R
5759import soy.iko.opencode.ui.components.relativeTime
5860import soy.iko.opencode.ui.vmFactory
5961
@@ -87,7 +89,7 @@ fun SessionListScreen(
8789 verticalAlignment = Alignment.CenterVertically,
8890 ) {
8991 Text(serverLabel, maxLines = 1, overflow = TextOverflow.Ellipsis)
90− Icon(Icons.Filled.ArrowDropDown, contentDescription = "Switch server")
92+ Icon(Icons.Filled.ArrowDropDown, contentDescription = stringResource(R.string.switch_server))
9193 }
9294 DropdownMenu(
9395 expanded = showServerMenu,
@@ -129,16 +131,16 @@ fun SessionListScreen(
129131 },
130132 actions = {
131133 IconButton(onClick = { vm.refresh() }) {
132− Icon(Icons.Filled.Refresh, contentDescription = "Refresh")
134+ Icon(Icons.Filled.Refresh, contentDescription = stringResource(R.string.refresh))
133135 }
134136 IconButton(onClick = onOpenFiles) {
135− Icon(Icons.Filled.Folder, contentDescription = "Files")
137+ Icon(Icons.Filled.Folder, contentDescription = stringResource(R.string.files))
136138 }
137139 IconButton(onClick = onOpenSettings) {
138− Icon(Icons.Filled.Settings, contentDescription = "Settings")
140+ Icon(Icons.Filled.Settings, contentDescription = stringResource(R.string.settings))
139141 }
140142 IconButton(onClick = onDisconnect) {
141− Icon(Icons.AutoMirrored.Filled.Logout, contentDescription = "Disconnect")
143+ Icon(Icons.AutoMirrored.Filled.Logout, contentDescription = stringResource(R.string.disconnect))
142144 }
143145 },
144146 )
@@ -147,7 +149,7 @@ fun SessionListScreen(
147149 ExtendedFloatingActionButton(
148150 onClick = { vm.createSession(onCreated = onOpenSession) },
149151 icon = { Icon(Icons.Filled.Add, contentDescription = null) },
150− text = { Text("New session") },
152+ text = { Text(stringResource(R.string.new_session)) },
151153 )
152154 },
153155 ) { padding ->
@@ -168,14 +170,14 @@ fun SessionListScreen(
168170 value = state.query,
169171 onValueChange = vm::setQuery,
170172 modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp, vertical = 8.dp),
171− placeholder = { Text("Search sessions…") },
173+ placeholder = { Text(stringResource(R.string.search_sessions)) },
172174 leadingIcon = { Icon(Icons.Filled.Search, contentDescription = null) },
173175 singleLine = true,
174176 )
175177 val sessions = state.filtered
176178 if (sessions.isEmpty()) {
177179 Text(
178− "No sessions match “${state.query}”.",
180+ stringResource(R.string.no_sessions_match, state.query),
179181 modifier = Modifier.padding(24.dp),
180182 color = MaterialTheme.colorScheme.onSurfaceVariant,
181183 )
@@ -204,17 +206,17 @@ fun SessionListScreen(
204206 pendingDelete?.let { session ->
205207 AlertDialog(
206208 onDismissRequest = { pendingDelete = null },
207− title = { Text("Delete session?") },
208− text = { Text("“${session.displayTitle}” will be permanently deleted. This cannot be undone.") },
209+ title = { Text(stringResource(R.string.delete_session_title)) },
210+ text = { Text(stringResource(R.string.delete_session_text, session.displayTitle)) },
209211 confirmButton = {
210212 TextButton(onClick = {
211213 haptics.performHapticFeedback(androidx.compose.ui.hapticfeedback.HapticFeedbackType.LongPress)
212214 pendingDelete = null
213215 vm.deleteSession(session)
214− }) { Text("Delete", color = MaterialTheme.colorScheme.error) }
216+ }) { Text(stringResource(R.string.delete), color = MaterialTheme.colorScheme.error) }
215217 },
216218 dismissButton = {
217− TextButton(onClick = { pendingDelete = null }) { Text("Cancel") }
219+ TextButton(onClick = { pendingDelete = null }) { Text(stringResource(R.string.cancel)) }
218220 },
219221 )
220222 }
@@ -243,21 +245,21 @@ private fun RenameSessionDialog(
243245) {
244246 AlertDialog(
245247 onDismissRequest = onDismiss,
246− title = { Text("Rename session") },
248+ title = { Text(stringResource(R.string.rename_session)) },
247249 text = {
248250 OutlinedTextField(
249251 value = title,
250252 onValueChange = onTitleChange,
251253 modifier = Modifier.fillMaxWidth(),
252− placeholder = { Text("Session title") },
254+ placeholder = { Text(stringResource(R.string.session_title_hint)) },
253255 singleLine = true,
254256 )
255257 },
256258 confirmButton = {
257− TextButton(onClick = onConfirm, enabled = title.isNotBlank()) { Text("Save") }
259+ TextButton(onClick = onConfirm, enabled = title.isNotBlank()) { Text(stringResource(R.string.save)) }
258260 },
259261 dismissButton = {
260− TextButton(onClick = onDismiss) { Text("Cancel") }
262+ TextButton(onClick = onDismiss) { Text(stringResource(R.string.cancel)) }
261263 },
262264 )
263265}
@@ -296,10 +298,10 @@ private fun SessionCard(
296298 )
297299 }
298300 IconButton(onClick = onRename) {
299− Icon(Icons.Filled.Edit, contentDescription = "Rename")
301+ Icon(Icons.Filled.Edit, contentDescription = stringResource(R.string.rename))
300302 }
301303 IconButton(onClick = onDelete) {
302− Icon(Icons.Filled.Delete, contentDescription = "Delete")
304+ Icon(Icons.Filled.Delete, contentDescription = stringResource(R.string.delete))
303305 }
304306 }
305307 if (!preview.isNullOrBlank()) {
@@ -329,17 +331,17 @@ private fun EmptySessions(onCreate: () -> Unit, modifier: Modifier = Modifier) {
329331 tint = MaterialTheme.colorScheme.onSurfaceVariant,
330332 )
331333 Spacer(Modifier.size(16.dp))
332− Text("No sessions yet", style = MaterialTheme.typography.titleMedium)
334+ Text(stringResource(R.string.no_sessions_yet), style = MaterialTheme.typography.titleMedium)
333335 Spacer(Modifier.size(8.dp))
334336 Text(
335− "Start a conversation with opencode.",
337+ stringResource(R.string.no_sessions_hint),
336338 style = MaterialTheme.typography.bodyMedium,
337339 color = MaterialTheme.colorScheme.onSurfaceVariant,
338340 )
339341 Spacer(Modifier.size(20.dp))
340342 Button(onClick = onCreate) {
341343 Icon(Icons.Filled.Add, contentDescription = null, modifier = Modifier.size(18.dp))
342− Text(" New session")
344+ Text(" " + stringResource(R.string.new_session))
343345 }
344346 }
345347}