Skip to content

Commit f94befb

Browse files
committed
feat: Implement internationalization support for UI components
1 parent 4fb3fd1 commit f94befb

11 files changed

Lines changed: 515 additions & 191 deletions

File tree

gradle.properties

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,5 @@ coroutines.version=1.10.2
1212

1313
api.version=1.10.0
1414
core.version=1.13.0
15-
ui.version=1.13.5
16-
app.version=1.3.4
15+
ui.version=1.14.0
16+
app.version=1.4.0

ui/src/main/kotlin/dev/paulee/ui/TextExplorerUI.kt

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ class TextExplorerUI(
7474

7575
@Composable
7676
private fun content() {
77+
val locale = LocalI18n.current
78+
7779
var textField by remember { mutableStateOf(TextFieldValue("")) }
7880
var selectedRows by remember { mutableStateOf(listOf<Map<String, String>>()) }
7981
var openWindow by remember { mutableStateOf(Window.NONE) }
@@ -96,7 +98,7 @@ class TextExplorerUI(
9698
var selectedText = remember(this.poolSelected) {
9799
val (pool, field) = dataService.getSelectedPool().split(".", limit = 2)
98100

99-
if (pool == "null") "No source available"
101+
if (pool == "null") locale["main.no_source"]
100102
else "$pool ($field)"
101103
}
102104

@@ -178,13 +180,13 @@ class TextExplorerUI(
178180

179181
IconDropDown(
180182
modifier = Modifier.align(Alignment.TopEnd),
181-
items = listOf("Load Plugin", "Load Data", "Plugin Info", "---", "Settings"),
183+
items = listOf("setting.load_plugin", "setting.load_data", "plugin.title", "---", "settings.title"),
182184
) {
183185
when (it) {
184-
"Load Plugin" -> openWindow = Window.LOAD_PLUGIN
185-
"Load Data" -> openWindow = Window.LOAD_DATA
186-
"Settings" -> openWindow = Window.SETTINGS
187-
"Plugin Info" -> openWindow = Window.PLUGIN_INFO
186+
"setting.load_plugin" -> openWindow = Window.LOAD_PLUGIN
187+
"setting.load_data" -> openWindow = Window.LOAD_DATA
188+
"plugin.title" -> openWindow = Window.PLUGIN_INFO
189+
"settings.title" -> openWindow = Window.SETTINGS
188190
}
189191
}
190192

@@ -222,7 +224,7 @@ class TextExplorerUI(
222224
showSuggestions = false
223225
}
224226
},
225-
placeholder = { Text("Search...") },
227+
placeholder = { Text(locale["main.search.placeholder"]) },
226228
modifier = Modifier
227229
.width(600.dp)
228230
.background(
@@ -289,7 +291,7 @@ class TextExplorerUI(
289291
showSuggestions = false
290292
showTable = false
291293
}) {
292-
Icon(Icons.Default.Close, contentDescription = "Close")
294+
Icon(Icons.Default.Close, contentDescription = locale["main.icon.close"])
293295
}
294296
}
295297
)
@@ -323,7 +325,7 @@ class TextExplorerUI(
323325
modifier = Modifier.height(70.dp).padding(horizontal = 10.dp),
324326
enabled = textField.text.isNotBlank() && dataService.hasSelectedPool()
325327
) {
326-
Icon(Icons.Default.Search, contentDescription = "Search")
328+
Icon(Icons.Default.Search, contentDescription = locale["main.icon.search"])
327329
}
328330
}
329331

@@ -335,7 +337,7 @@ class TextExplorerUI(
335337
) inner@{
336338
if (totalPages == 0L) {
337339
Text(
338-
"No results were found.",
340+
locale["main.no_results"],
339341
fontSize = 24.sp,
340342
modifier = Modifier.align(Alignment.CenterHorizontally).padding(16.dp)
341343
)
@@ -395,7 +397,7 @@ class TextExplorerUI(
395397
)
396398

397399
if (totalPages < 2) {
398-
Text("Total: $amount", modifier = Modifier.align(Alignment.CenterHorizontally))
400+
Text(locale["main.total", amount], modifier = Modifier.align(Alignment.CenterHorizontally))
399401
return@inner
400402
}
401403

@@ -420,10 +422,10 @@ class TextExplorerUI(
420422
}
421423
}, enabled = currentPage > 0
422424
) {
423-
Icon(Icons.AutoMirrored.Filled.KeyboardArrowLeft, contentDescription = "Left")
425+
Icon(Icons.AutoMirrored.Filled.KeyboardArrowLeft, contentDescription = locale["main.nav.left"])
424426
}
425427

426-
Text("Page ${currentPage + 1} of $totalPages (Total: $amount)")
428+
Text(locale["main.page_info", currentPage + 1, totalPages, amount])
427429

428430
IconButton(
429431
onClick = {
@@ -439,7 +441,7 @@ class TextExplorerUI(
439441
}
440442
}, enabled = currentPage < totalPages - 1
441443
) {
442-
Icon(Icons.AutoMirrored.Filled.KeyboardArrowRight, contentDescription = "Right")
444+
Icon(Icons.AutoMirrored.Filled.KeyboardArrowRight, contentDescription = locale["main.nav.right"])
443445
}
444446
}
445447
}
@@ -480,8 +482,8 @@ class TextExplorerUI(
480482
) {
481483
Icon(
482484
imageVector = Icons.Filled.CheckCircle,
483-
contentDescription = "Success",
484-
tint = Color(0xFF388E3C),
485+
contentDescription =locale["main.status.success"],
486+
tint = App.Colors.GREEN_HIGHLIGHT.toComposeColor(),
485487
modifier = Modifier.size(24.dp)
486488
)
487489

@@ -506,14 +508,14 @@ class TextExplorerUI(
506508
) {
507509
Icon(
508510
imageVector = Icons.Filled.Warning,
509-
contentDescription = "Error",
511+
contentDescription = locale["main.status.error"],
510512
tint = Color(0xFFD32F2F),
511513
modifier = Modifier.size(24.dp)
512514
)
513515

514516
Text(
515517
text = (loadState as LoadState.Error).message,
516-
color = Color(0xFFD32F2F)
518+
color = App.Colors.RED_HIGHLIGHT.toComposeColor()
517519
)
518520
}
519521
LaunchedEffect(loadState) {
@@ -550,12 +552,12 @@ class TextExplorerUI(
550552
if (dataInfo == null) return@DataLoaderWindow
551553

552554
scope.launch {
553-
loadState = LoadState.Loading("Loading data pool")
555+
loadState = LoadState.Loading(locale["main.loading"])
554556

555557
val poolsEmpty = dataService.getAvailablePools().isEmpty()
556558

557559
val success = dataService.createDataPool(dataInfo, dataDir) { progress ->
558-
loadState = LoadState.Loading("Loading data pool ($progress %)")
560+
loadState = LoadState.Loading(locale["main.loading_progress", progress])
559561
}
560562

561563
loadState = if (success) {
@@ -566,8 +568,8 @@ class TextExplorerUI(
566568
poolSelected = !poolSelected
567569
}
568570

569-
LoadState.Success("Successfully loaded data pool '${dataInfo.name}'")
570-
} else LoadState.Error("Failed to create data pool")
571+
LoadState.Success(locale["main.success_load", dataInfo.name])
572+
} else LoadState.Error(locale["main.error_load"])
571573
}
572574
}
573575

ui/src/main/kotlin/dev/paulee/ui/components/Dialog.kt

Lines changed: 44 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import androidx.compose.ui.unit.dp
88
import androidx.compose.ui.window.AwtWindow
99
import androidx.compose.ui.window.Dialog
1010
import androidx.compose.ui.window.DialogProperties
11+
import dev.paulee.ui.LocalI18n
1112
import dev.paulee.ui.SimpleTextField
1213
import java.awt.FileDialog
1314
import java.awt.Frame
@@ -24,45 +25,49 @@ fun FileDialog(
2425
dialogType: DialogType = DialogType.LOAD,
2526
extension: String? = null,
2627
onCloseRequest: (result: List<Path>) -> Unit,
27-
) = AwtWindow(
28-
create = {
29-
object :
30-
FileDialog(parent, if (dialogType == DialogType.SAVE) "Save file" else "Open file", dialogType.ordinal) {
28+
) {
29+
val locale = LocalI18n.current
3130

32-
init {
33-
isMultipleMode = dialogType == DialogType.LOAD
31+
AwtWindow(
32+
create = {
33+
object :
34+
FileDialog(parent, if (dialogType == DialogType.SAVE) locale["dialog.save"] else locale["dialog.open"], dialogType.ordinal) {
3435

35-
if (!extension.isNullOrBlank()) {
36-
filenameFilter = FilenameFilter { _, name ->
37-
name.endsWith(".$extension", ignoreCase = true)
38-
}
36+
init {
37+
isMultipleMode = dialogType == DialogType.LOAD
38+
39+
if (!extension.isNullOrBlank()) {
40+
filenameFilter = FilenameFilter { _, name ->
41+
name.endsWith(".$extension", ignoreCase = true)
42+
}
3943

40-
if (dialogType == DialogType.SAVE) file = "untitled"
44+
if (dialogType == DialogType.SAVE) file = "untitled"
45+
}
4146
}
42-
}
4347

44-
override fun setVisible(value: Boolean) {
45-
super.setVisible(value)
48+
override fun setVisible(value: Boolean) {
49+
super.setVisible(value)
4650

47-
if (value) {
48-
val paths = files.map {
49-
val path = it.toPath()
51+
if (value) {
52+
val paths = files.map {
53+
val path = it.toPath()
5054

51-
if (dialogType == DialogType.SAVE && extension != null && !path.toString().lowercase()
52-
.endsWith(".$extension")
53-
) {
54-
Path.of("${path}.$extension")
55-
} else {
56-
path
57-
}
58-
}.toList()
55+
if (dialogType == DialogType.SAVE && extension != null && !path.toString().lowercase()
56+
.endsWith(".$extension")
57+
) {
58+
Path.of("${path}.$extension")
59+
} else {
60+
path
61+
}
62+
}.toList()
5963

60-
onCloseRequest(paths)
64+
onCloseRequest(paths)
65+
}
6166
}
6267
}
63-
}
64-
}, dispose = FileDialog::dispose
65-
)
68+
}, dispose = FileDialog::dispose
69+
)
70+
}
6671

6772
@Composable
6873
fun CustomInputDialog(
@@ -73,6 +78,8 @@ fun CustomInputDialog(
7378
textFieldValue: String,
7479
onTextFieldValueChange: (String) -> Unit,
7580
) {
81+
val locale = LocalI18n.current
82+
7683
Dialog(
7784
onDismissRequest = onDismissRequest,
7885
properties = DialogProperties(dismissOnBackPress = true, dismissOnClickOutside = true)
@@ -101,15 +108,15 @@ fun CustomInputDialog(
101108
horizontalArrangement = Arrangement.End
102109
) {
103110
TextButton(onClick = onDismissRequest) {
104-
Text("Cancel")
111+
Text(locale["input.cancel"])
105112
}
106113

107114
Spacer(modifier = Modifier.width(8.dp))
108115

109116
Button(
110117
onClick = { onConfirmClick(textFieldValue) }, enabled = textFieldValue.isNotBlank()
111118
) {
112-
Text("OK")
119+
Text(locale["input.confirm"])
113120
}
114121
}
115122
}
@@ -124,6 +131,8 @@ fun YesNoDialog(
124131
onDismissRequest: () -> Unit,
125132
onResult: (Boolean) -> Unit,
126133
) {
134+
val locale = LocalI18n.current
135+
127136
Dialog(
128137
onDismissRequest = onDismissRequest,
129138
properties = DialogProperties(dismissOnBackPress = true, dismissOnClickOutside = true)
@@ -145,14 +154,16 @@ fun YesNoDialog(
145154
onResult(false)
146155
onDismissRequest()
147156
}) {
148-
Text("No")
157+
Text(locale["dialog.no"])
149158
}
159+
150160
Spacer(modifier = Modifier.width(8.dp))
161+
151162
Button(onClick = {
152163
onResult(true)
153164
onDismissRequest()
154165
}) {
155-
Text("Yes")
166+
Text(locale["dialog.yes"])
156167
}
157168
}
158169
}

0 commit comments

Comments
 (0)