lang for toolchain
This commit is contained in:
parent
ee5a2463b9
commit
b485c1e48c
10 changed files with 85 additions and 93 deletions
|
@ -22,6 +22,7 @@
|
|||
|
||||
package com.falsepattern.zigbrains.project.toolchain.base
|
||||
|
||||
import com.falsepattern.zigbrains.ZigBrainsBundle
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.ui.components.JBTextField
|
||||
import com.intellij.ui.dsl.builder.AlignX
|
||||
|
@ -35,7 +36,7 @@ abstract class ZigToolchainPanel<T: ZigToolchain>: Disposable {
|
|||
set(value) {nameField.text = value ?: ""}
|
||||
|
||||
open fun attach(p: Panel): Unit = with(p) {
|
||||
row("Name") {
|
||||
row(ZigBrainsBundle.message("settings.toolchain.base.name.label")) {
|
||||
cell(nameField).resizableColumn().align(AlignX.FILL)
|
||||
}
|
||||
separator()
|
||||
|
|
|
@ -53,12 +53,11 @@ import javax.swing.DefaultComboBoxModel
|
|||
import javax.swing.JList
|
||||
import javax.swing.event.DocumentEvent
|
||||
|
||||
//TODO lang
|
||||
object Downloader {
|
||||
suspend fun downloadToolchain(component: Component): ZigToolchain? {
|
||||
val info = withModalProgress(
|
||||
ModalTaskOwner.component(component),
|
||||
"Fetching zig version information",
|
||||
ZigBrainsBundle.message("settings.toolchain.downloader.progress.fetch"),
|
||||
TaskCancellation.cancellable()
|
||||
) {
|
||||
ZigVersionInfo.downloadVersionList()
|
||||
|
@ -68,7 +67,7 @@ object Downloader {
|
|||
} ?: return null
|
||||
withModalProgress(
|
||||
ModalTaskOwner.component(component),
|
||||
"Installing Zig ${version.version}",
|
||||
ZigBrainsBundle.message("settings.toolchain.downloader.progress.install", version.version.rawVersion),
|
||||
TaskCancellation.cancellable()
|
||||
) {
|
||||
version.downloadAndUnpack(downloadPath)
|
||||
|
@ -94,7 +93,7 @@ object Downloader {
|
|||
val outputPath = textFieldWithBrowseButton(
|
||||
null,
|
||||
FileChooserDescriptorFactory.createSingleFolderDescriptor()
|
||||
.withTitle(ZigBrainsBundle.message("dialog.title.zig-toolchain"))
|
||||
.withTitle(ZigBrainsBundle.message("settings.toolchain.downloader.chooser.title"))
|
||||
)
|
||||
Disposer.register(dialog, outputPath)
|
||||
outputPath.textField.columns = 50
|
||||
|
@ -110,14 +109,14 @@ object Downloader {
|
|||
errorMessageBox.icon = AllIcons.General.Error
|
||||
dialog.setOkActionEnabled(false)
|
||||
}
|
||||
errorMessageBox.text = when(state) {
|
||||
DirectoryState.Invalid -> "Invalid path"
|
||||
DirectoryState.NotAbsolute -> "Must be an absolute path"
|
||||
DirectoryState.NotDirectory -> "Path is not a directory"
|
||||
DirectoryState.NotEmpty -> "Directory is not empty"
|
||||
DirectoryState.CreateNew -> "Directory will be created"
|
||||
DirectoryState.Ok -> "Directory OK"
|
||||
}
|
||||
errorMessageBox.text = ZigBrainsBundle.message(when(state) {
|
||||
DirectoryState.Invalid -> "settings.toolchain.downloader.state.invalid"
|
||||
DirectoryState.NotAbsolute -> "settings.toolchain.downloader.state.not-absolute"
|
||||
DirectoryState.NotDirectory -> "settings.toolchain.downloader.state.not-directory"
|
||||
DirectoryState.NotEmpty -> "settings.toolchain.downloader.state.not-empty"
|
||||
DirectoryState.CreateNew -> "settings.toolchain.downloader.state.create-new"
|
||||
DirectoryState.Ok -> "settings.toolchain.downloader.state.ok"
|
||||
})
|
||||
dialog.window.repaint()
|
||||
}
|
||||
outputPath.whenFocusGained {
|
||||
|
@ -133,16 +132,16 @@ object Downloader {
|
|||
outputPath.text = System.getProperty("user.home") + "/.zig/" + item.version
|
||||
val size = item.dist.size
|
||||
val sizeMb = size / (1024f * 1024f)
|
||||
archiveSizeCell?.comment?.text = "Archive size: %.2fMB".format(sizeMb)
|
||||
archiveSizeCell?.comment?.text = ZigBrainsBundle.message("settings.toolchain.downloader.archive-size.text", "%.2fMB".format(sizeMb))
|
||||
}
|
||||
theList.addItemListener {
|
||||
detect(it.item as ZigVersionInfo)
|
||||
}
|
||||
val center = panel {
|
||||
row("Version:") {
|
||||
row(ZigBrainsBundle.message("settings.toolchain.downloader.version.label")) {
|
||||
cell(theList).resizableColumn().align(AlignX.FILL)
|
||||
}
|
||||
row("Location:") {
|
||||
row(ZigBrainsBundle.message("settings.toolchain.downloader.location.label")) {
|
||||
cell(outputPath).resizableColumn().align(AlignX.FILL).apply { archiveSizeCell = comment("") }
|
||||
}
|
||||
row {
|
||||
|
@ -152,9 +151,9 @@ object Downloader {
|
|||
}
|
||||
detect(info[0])
|
||||
dialog.centerPanel(center)
|
||||
dialog.setTitle("Zig Downloader")
|
||||
dialog.setTitle(ZigBrainsBundle.message("settings.toolchain.downloader.title"))
|
||||
dialog.addCancelAction()
|
||||
dialog.addOkAction().also { it.setText("Download") }
|
||||
dialog.addOkAction().also { it.setText(ZigBrainsBundle.message("settings.toolchain.downloader.ok-action")) }
|
||||
if (!dialog.showAndGet()) {
|
||||
return null
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@ object LocalSelector {
|
|||
val path = textFieldWithBrowseButton(
|
||||
null,
|
||||
FileChooserDescriptorFactory.createSingleFolderDescriptor()
|
||||
.withTitle(ZigBrainsBundle.message("dialog.title.zig-toolchain"))
|
||||
.withTitle(ZigBrainsBundle.message("settings.toolchain.local-selector.chooser.title"))
|
||||
)
|
||||
Disposer.register(dialog, path)
|
||||
path.textField.columns = 50
|
||||
|
@ -65,7 +65,7 @@ object LocalSelector {
|
|||
val tc = LocalZigToolchain.tryFromPathString(path.text)
|
||||
if (tc == null) {
|
||||
errorMessageBox.icon = AllIcons.General.Error
|
||||
errorMessageBox.text = "Invalid toolchain path"
|
||||
errorMessageBox.text = ZigBrainsBundle.message("settings.toolchain.local-selector.state.invalid")
|
||||
dialog.setOkActionEnabled(false)
|
||||
} else if (ZigToolchainListService
|
||||
.getInstance()
|
||||
|
@ -74,17 +74,18 @@ object LocalSelector {
|
|||
.any { it.location == tc.location }
|
||||
) {
|
||||
errorMessageBox.icon = AllIcons.General.Warning
|
||||
errorMessageBox.text = tc.name?.let { "Toolchain already exists as \"$it\"" } ?: "Toolchain already exists"
|
||||
errorMessageBox.text = tc.name?.let { ZigBrainsBundle.message("settings.toolchain.local-selector.state.already-exists-named", it) }
|
||||
?: ZigBrainsBundle.message("settings.toolchain.local-selector.state.already-exists-unnamed")
|
||||
dialog.setOkActionEnabled(true)
|
||||
} else {
|
||||
errorMessageBox.icon = Icons.Zig
|
||||
errorMessageBox.text = tc.name ?: "OK"
|
||||
errorMessageBox.text = tc.name ?: ZigBrainsBundle.message("settings.toolchain.local-selector.state.ok")
|
||||
dialog.setOkActionEnabled(true)
|
||||
}
|
||||
}
|
||||
})
|
||||
val center = panel {
|
||||
row("Path:") {
|
||||
row(ZigBrainsBundle.message("settings.toolchain.local-selector.path.label")) {
|
||||
cell(path).resizableColumn().align(AlignX.FILL)
|
||||
}
|
||||
row {
|
||||
|
@ -93,9 +94,9 @@ object LocalSelector {
|
|||
}
|
||||
}
|
||||
dialog.centerPanel(center)
|
||||
dialog.setTitle("Zig Browser")
|
||||
dialog.setTitle(ZigBrainsBundle.message("settings.toolchain.local-selector.title"))
|
||||
dialog.addCancelAction()
|
||||
dialog.addOkAction().also { it.setText("Add") }
|
||||
dialog.addOkAction().also { it.setText(ZigBrainsBundle.message("settings.toolchain.local-selector.ok-action")) }
|
||||
if (!dialog.showAndGet()) {
|
||||
return null
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
package com.falsepattern.zigbrains.project.toolchain.downloader
|
||||
|
||||
import com.falsepattern.zigbrains.ZigBrainsBundle
|
||||
import com.falsepattern.zigbrains.shared.Unarchiver
|
||||
import com.intellij.openapi.application.PathManager
|
||||
import com.intellij.openapi.progress.EmptyProgressIndicator
|
||||
|
@ -85,7 +86,7 @@ data class ZigVersionInfo(
|
|||
val service = DownloadableFileService.getInstance()
|
||||
val tempFile = FileUtil.createTempFile(tempPluginDir, "index", ".json", false, false)
|
||||
val desc = service.createFileDescription("https://ziglang.org/download/index.json", tempFile.name)
|
||||
val downloader = service.createDownloader(listOf(desc), "Zig version information")
|
||||
val downloader = service.createDownloader(listOf(desc), ZigBrainsBundle.message("settings.toolchain.downloader.service.index"))
|
||||
val downloadResults = coroutineToIndicator {
|
||||
downloader.download(tempPluginDir)
|
||||
}
|
||||
|
@ -110,7 +111,7 @@ private suspend fun downloadTarball(dist: ZigVersionInfo.Tarball, into: Path, re
|
|||
val fileName = dist.tarball.substringAfterLast('/')
|
||||
val tempFile = FileUtil.createTempFile(into.toFile(), "tarball", fileName, false, false)
|
||||
val desc = service.createFileDescription(dist.tarball, tempFile.name)
|
||||
val downloader = service.createDownloader(listOf(desc), "Zig tarball")
|
||||
val downloader = service.createDownloader(listOf(desc), ZigBrainsBundle.message("settings.toolchain.downloader.service.tarball"))
|
||||
val downloadResults = reporter.sizedStep(100) {
|
||||
coroutineToIndicator {
|
||||
downloader.download(into.toFile())
|
||||
|
@ -131,7 +132,7 @@ private suspend fun flattenDownloadDir(dir: Path, reporter: ProgressReporter) {
|
|||
coroutineToIndicator {
|
||||
val indicator = ProgressManager.getInstance().progressIndicator ?: EmptyProgressIndicator()
|
||||
indicator.isIndeterminate = true
|
||||
indicator.text = "Flattening directory"
|
||||
indicator.text = ZigBrainsBundle.message("settings.toolchain.downloader.progress.flatten")
|
||||
Files.newDirectoryStream(src).use { stream ->
|
||||
stream.forEach {
|
||||
indicator.text2 = it.name
|
||||
|
|
|
@ -77,13 +77,13 @@ class LocalZigToolchainPanel() : ZigToolchainPanel<LocalZigToolchain>() {
|
|||
|
||||
override fun attach(p: Panel): Unit = with(p) {
|
||||
super.attach(p)
|
||||
row(ZigBrainsBundle.message("settings.project.label.toolchain")) {
|
||||
row(ZigBrainsBundle.message("settings.toolchain.local.path.label")) {
|
||||
cell(pathToToolchain).resizableColumn().align(AlignX.FILL)
|
||||
}
|
||||
row(ZigBrainsBundle.message("settings.project.label.toolchain-version")) {
|
||||
row(ZigBrainsBundle.message("settings.toolchain.local.version.label")) {
|
||||
cell(toolchainVersion)
|
||||
}
|
||||
row(ZigBrainsBundle.message("settings.project.label.std-location")) {
|
||||
row(ZigBrainsBundle.message("settings.toolchain.local.std.label")) {
|
||||
cell(pathToStd).resizableColumn().align(AlignX.FILL)
|
||||
cell(stdFieldOverride)
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
package com.falsepattern.zigbrains.project.toolchain.ui
|
||||
|
||||
import com.falsepattern.zigbrains.ZigBrainsBundle
|
||||
import com.falsepattern.zigbrains.project.toolchain.ZigToolchainListService
|
||||
import com.falsepattern.zigbrains.project.toolchain.ZigToolchainService
|
||||
import com.falsepattern.zigbrains.project.toolchain.base.suggestZigToolchains
|
||||
|
@ -58,7 +59,7 @@ import kotlin.collections.addAll
|
|||
class ZigToolchainEditor(private val project: Project): Configurable {
|
||||
private var myUi: UI? = null
|
||||
override fun getDisplayName(): @NlsContexts.ConfigurableName String? {
|
||||
return "Zig"
|
||||
return ZigBrainsBundle.message("settings.toolchain.editor.display-name")
|
||||
}
|
||||
|
||||
override fun createComponent(): JComponent? {
|
||||
|
@ -150,9 +151,9 @@ class ZigToolchainEditor(private val project: Project): Configurable {
|
|||
}
|
||||
|
||||
fun attach(p: Panel): Unit = with(p) {
|
||||
row("Toolchain") {
|
||||
row(ZigBrainsBundle.message("settings.toolchain.editor.toolchain.label")) {
|
||||
cell(toolchainBox).resizableColumn().align(AlignX.FILL)
|
||||
button("Funny") { e ->
|
||||
button(ZigBrainsBundle.message("settings.toolchain.editor.toolchain.edit-button.name")) { e ->
|
||||
zigCoroutineScope.launchWithEDT(toolchainBox.asContextElement()) {
|
||||
val config = ZigToolchainListEditor()
|
||||
var inited = false
|
||||
|
@ -211,7 +212,7 @@ private fun getModelList(): List<TCListElemIn> {
|
|||
modelList.addAll(ZigToolchainListService.getInstance().toolchains.map { it.asActual() })
|
||||
modelList.add(Separator("", true))
|
||||
modelList.addAll(TCListElem.fetchGroup)
|
||||
modelList.add(Separator("Detected toolchains", true))
|
||||
modelList.add(Separator(ZigBrainsBundle.message("settings.toolchain.model.detected.separator"), true))
|
||||
modelList.addAll(suggestZigToolchains().map { it.asSuggested() })
|
||||
return modelList
|
||||
}
|
|
@ -86,11 +86,11 @@ class ZigToolchainListEditor : MasterDetailsComponent(), ZigToolchainListService
|
|||
}
|
||||
|
||||
override fun createActions(fromPopup: Boolean): List<AnAction> {
|
||||
val add = object : DumbAwareAction({ "lmaoo" }, Presentation.NULL_STRING, IconUtil.addIcon) {
|
||||
val add = object : DumbAwareAction({ ZigBrainsBundle.message("settings.toolchain.list.add-action.name") }, Presentation.NULL_STRING, IconUtil.addIcon) {
|
||||
override fun actionPerformed(e: AnActionEvent) {
|
||||
val modelList = ArrayList<TCListElemIn>()
|
||||
modelList.addAll(TCListElem.fetchGroup)
|
||||
modelList.add(Separator("Detected toolchains", true))
|
||||
modelList.add(Separator(ZigBrainsBundle.message("settings.toolchain.model.detected.separator"), true))
|
||||
modelList.addAll(suggestZigToolchains().map { it.asSuggested() })
|
||||
val model = TCModel.Companion(modelList)
|
||||
val context = TCContext(null, model)
|
||||
|
@ -134,9 +134,9 @@ class ZigToolchainListEditor : MasterDetailsComponent(), ZigToolchainListService
|
|||
super.reset()
|
||||
}
|
||||
|
||||
override fun getEmptySelectionString() = ZigBrainsBundle.message("settings.toolchains.empty")
|
||||
override fun getEmptySelectionString() = ZigBrainsBundle.message("settings.toolchain.list.empty")
|
||||
|
||||
override fun getDisplayName() = ZigBrainsBundle.message("settings.toolchains.title")
|
||||
override fun getDisplayName() = ZigBrainsBundle.message("settings.toolchain.list.title")
|
||||
|
||||
private fun addToolchain(uuid: UUID, toolchain: ZigToolchain) {
|
||||
val node = MyNode(toolchain.createNamedConfigurable(uuid))
|
||||
|
|
|
@ -24,6 +24,7 @@ package com.falsepattern.zigbrains.project.toolchain.ui
|
|||
|
||||
import ai.grazie.utils.attributes.value
|
||||
import com.falsepattern.zigbrains.Icons
|
||||
import com.falsepattern.zigbrains.ZigBrainsBundle
|
||||
import com.falsepattern.zigbrains.project.toolchain.base.render
|
||||
import com.intellij.icons.AllIcons
|
||||
import com.intellij.openapi.project.Project
|
||||
|
@ -208,17 +209,17 @@ internal class TCCellRenderer(val getModel: () -> TCModel) : ColoredListCellRend
|
|||
|
||||
is TCListElem.Download -> {
|
||||
icon = AllIcons.Actions.Download
|
||||
append("Download Zig\u2026")
|
||||
append(ZigBrainsBundle.message("settings.toolchain.model.download.text"))
|
||||
}
|
||||
|
||||
is TCListElem.FromDisk -> {
|
||||
icon = AllIcons.General.OpenDisk
|
||||
append("Add Zig from disk\u2026")
|
||||
append(ZigBrainsBundle.message("settings.toolchain.model.from-disk.text"))
|
||||
}
|
||||
|
||||
is TCListElem.None, null -> {
|
||||
icon = AllIcons.General.BalloonError
|
||||
append("<No Toolchain>", SimpleTextAttributes.ERROR_ATTRIBUTES)
|
||||
append(ZigBrainsBundle.message("settings.toolchain.model.none.text"), SimpleTextAttributes.ERROR_ATTRIBUTES)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,49 +0,0 @@
|
|||
/*
|
||||
* This file is part of ZigBrains.
|
||||
*
|
||||
* Copyright (C) 2023-2025 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* ZigBrains is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, only version 3 of the License.
|
||||
*
|
||||
* ZigBrains is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.falsepattern.zigbrains.project.toolchain.ui.popup
|
||||
|
||||
import com.falsepattern.zigbrains.Icons
|
||||
import com.falsepattern.zigbrains.project.toolchain.base.render
|
||||
import com.falsepattern.zigbrains.project.toolchain.ui.Separator
|
||||
import com.falsepattern.zigbrains.project.toolchain.ui.TCListElem
|
||||
import com.falsepattern.zigbrains.project.toolchain.ui.TCListElemIn
|
||||
import com.intellij.icons.AllIcons
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.ui.CellRendererPanel
|
||||
import com.intellij.ui.CollectionListModel
|
||||
import com.intellij.ui.ColoredListCellRenderer
|
||||
import com.intellij.ui.GroupHeaderSeparator
|
||||
import com.intellij.ui.SimpleColoredComponent
|
||||
import com.intellij.ui.components.panels.OpaquePanel
|
||||
import com.intellij.ui.popup.list.ComboBoxPopup
|
||||
import com.intellij.util.Consumer
|
||||
import com.intellij.util.ui.EmptyIcon
|
||||
import com.intellij.util.ui.JBUI
|
||||
import com.intellij.util.ui.UIUtil
|
||||
import java.awt.BorderLayout
|
||||
import java.awt.Component
|
||||
import java.util.IdentityHashMap
|
||||
import javax.accessibility.AccessibleContext
|
||||
import javax.swing.JList
|
||||
import javax.swing.border.Border
|
||||
|
|
@ -98,8 +98,6 @@ settings.project.label.toolchain=Toolchain location
|
|||
settings.project.label.toolchain-version=Detected zig version
|
||||
settings.project.label.override-std=Override standard library
|
||||
settings.project.label.std-location=Standard library location
|
||||
settings.toolchains.empty=Select a toolchain to view or edit its details here
|
||||
settings.toolchains.title=Toolchains
|
||||
toolwindow.stripe.zigbrains.build=Zig
|
||||
build.tool.window.tree.steps.label=Steps
|
||||
build.tool.window.tree.build.label=Active builds
|
||||
|
@ -112,3 +110,42 @@ build.tool.window.status.error.general=Error while running zig build -l
|
|||
build.tool.window.status.no-builds=No builds currently in progress
|
||||
build.tool.window.status.timeout=zig build -l timed out after {0} seconds.
|
||||
zig=Zig
|
||||
settings.toolchain.base.name.label=Name
|
||||
settings.toolchain.local.path.label=Toolchain location
|
||||
settings.toolchain.local.version.label=Detected zig version
|
||||
settings.toolchain.local.std.label=Override standard library
|
||||
settings.toolchain.editor.display-name=Zig
|
||||
settings.toolchain.editor.toolchain.label=Toolchain
|
||||
settings.toolchain.editor.toolchain.edit-button.name=Edit
|
||||
settings.toolchain.model.detected.separator=Detected toolchains
|
||||
settings.toolchain.model.none.text=<No Toolchain>
|
||||
settings.toolchain.model.from-disk.text=Add Zig from disk\u2026
|
||||
settings.toolchain.model.download.text=Download Zig\u2026
|
||||
settings.toolchain.list.title=Toolchains
|
||||
settings.toolchain.list.add-action.name=Add New
|
||||
settings.toolchain.list.empty=Select a toolchain to view or edit its details here
|
||||
settings.toolchain.downloader.title=Install Zig
|
||||
settings.toolchain.downloader.version.label=Version:
|
||||
settings.toolchain.downloader.location.label=Location:
|
||||
settings.toolchain.downloader.ok-action=Download
|
||||
settings.toolchain.downloader.progress.fetch=Fetching zig version information
|
||||
settings.toolchain.downloader.progress.install=Installing Zig {0}
|
||||
settings.toolchain.downloader.progress.flatten=Flattening unpacked archive
|
||||
settings.toolchain.downloader.chooser.title=Zig Install Directory
|
||||
settings.toolchain.downloader.state.invalid=Invalid path
|
||||
settings.toolchain.downloader.state.not-absolute=Must be an absolute path
|
||||
settings.toolchain.downloader.state.not-directory=Path is not a directory
|
||||
settings.toolchain.downloader.state.not-empty=Directory is not empty
|
||||
settings.toolchain.downloader.state.create-new=Directory will be created
|
||||
settings.toolchain.downloader.state.ok=Directory OK
|
||||
settings.toolchain.downloader.archive-size.text=Archive size: {0}
|
||||
settings.toolchain.downloader.service.index=Zig version information
|
||||
settings.toolchain.downloader.service.tarball=Zig archive
|
||||
settings.toolchain.local-selector.title=Select Zig From Disk
|
||||
settings.toolchain.local-selector.path.label=Path:
|
||||
settings.toolchain.local-selector.ok-action=Add
|
||||
settings.toolchain.local-selector.chooser.title=Existing Zig Install Directory
|
||||
settings.toolchain.local-selector.state.invalid=Invalid toolchain path
|
||||
settings.toolchain.local-selector.state.already-exists-unnamed=Toolchain already exists
|
||||
settings.toolchain.local-selector.state.already-exists-named=Toolchain already exists as "{0}"
|
||||
settings.toolchain.local-selector.state.ok=OK
|
Loading…
Add table
Reference in a new issue