Wizard: fix layout & text problems

This commit is contained in:
Ilya Kirillov
2020-04-07 16:30:28 +03:00
parent c313916044
commit c1f40907db
13 changed files with 99 additions and 69 deletions
@@ -1,21 +1,20 @@
generator.title=Kotlin (Experimental Wizard) generator.title=Kotlin (Experimental Wizard)
error.nothing.selected=Neither module nor source set is selected error.nothing.selected=No module is selected. Select module or source set to configure.
project.preview=Preview project.preview=Project Structure
additional.buildsystem.settings.kotlin.runtime=Kotlin Runtime additional.buildsystem.settings.kotlin.runtime=Kotlin Runtime
additional.buildsystem.settings.project.jdk=Project JDK additional.buildsystem.settings.project.jdk=Project JDK
additional.buildsystem.settings.artifact.coordinates=Artifact Coordinates additional.buildsystem.settings.artifact.coordinates=Artifact Coordinates
module.dependencies.module.dependencies=Module dependencies module.dependencies.module.dependencies=Module dependencies
module.dependencies.add.module.dependency=Add module dependency module.dependencies.add.module.dependency=Add Module Dependency
module.dependencies.remove.module.dependency=Remove module dependency module.dependencies.remove.module.dependency=Remove Module Dependency
editor.modules.add=Add {0} editor.modules.add=Add {0}
editor.modules.remove.selected.module=Do you want to remove selected {0} editor.modules.remove.selected.module=Do you want to remove {0} module with all submodules?
editor.modules.remove.selected.submodules=This will also remove all submodules. editor.modules.remove.selected.target=Do you want to remove {0} target?
editor.modules.remove.selected.no.undone=This action cannot be undone. editor.modules.remove.selected.question=Remove {0}
editor.modules.remove.selected.question=Remove selected {0}?
editor.modules.remove.selected.remove=Remove editor.modules.remove.selected.remove=Remove
editor.modules.remove.selected.cancel=Cancel editor.modules.remove.selected.cancel=Cancel
editor.modules.remove.tooltip=Remove {0} editor.modules.remove.tooltip=Remove {0}
@@ -25,12 +24,13 @@ editor.modules.add.module=Add a module to the project
editor.modules.no.modules=No modules created editor.modules.no.modules=No modules created
module.settings.name=Name module.settings.name=Name
module.settings.name.same.as.project=[The same as the project name] module.settings.name.same.as.project=<The same as the project name>
module.settings.name.can.not.be.modified=[Can not be modified] module.settings.name.can.not.be.modified=<Can not be modified>
module.settings.name.module.name=Module name module.settings.name.module.name=Module name
module.settings.template=Template module.settings.template=Template
module.settings.template.none=None module.settings.template.none=None
version.provider.downloading.kotlin.version=Downloading Kotlin version version.provider.downloading.kotlin.version=Downloading Kotlin version
module.settings.dependencies.empty=There is no module dependencies module.settings.dependencies.empty=No module dependencies added.
module.settings.dependencies.empty.suggest.add=Add module dependency
@@ -32,7 +32,7 @@ class TextFieldComponent(
fun disable(@Nls message: String) { fun disable(@Nls message: String) {
cachedValueWhenDisabled = getUiValue() cachedValueWhenDisabled = getUiValue()
uiComponent.isEditable = false uiComponent.isEditable = false
uiComponent.foreground = UIUtil.getLabelFontColor(UIUtil.FontColor.BRIGHTER) uiComponent.foreground = UIUtil.getLabelDisabledForeground()
isDisabled = true isDisabled = true
updateUiValue(message) updateUiValue(message)
} }
@@ -38,7 +38,7 @@ class BuildSystemTypeSettingComponent(
BuildSystemPlugin::type.reference, BuildSystemPlugin::type.reference,
context context
), Disposable { ), Disposable {
override val forceLabelCenteringOffset: Int? = 2 override val forceLabelCenteringOffset: Int? = 3
private val buttons by lazy(LazyThreadSafetyMode.NONE) { private val buttons by lazy(LazyThreadSafetyMode.NONE) {
read { setting.type.values.filter { setting.type.filter(this, reference, it) }.map(::BuildSystemChooseButton) } read { setting.type.values.filter { setting.type.filter(this, reference, it) }.map(::BuildSystemChooseButton) }
} }
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.setting.createSettingC
import java.awt.Cursor import java.awt.Cursor
import java.awt.event.MouseAdapter import java.awt.event.MouseAdapter
import java.awt.event.MouseEvent import java.awt.event.MouseEvent
import javax.swing.BorderFactory
import javax.swing.JComponent import javax.swing.JComponent
class FirstWizardStepComponent(ideWizard: IdeWizard) : WizardStepComponent(ideWizard.context) { class FirstWizardStepComponent(ideWizard: IdeWizard) : WizardStepComponent(ideWizard.context) {
@@ -200,10 +201,15 @@ private class KotlinRuntimeComponentComponent(ideWizard: IdeWizard) : TitledComp
@Suppress("SpellCheckingInspection") @Suppress("SpellCheckingInspection")
private class HideableSection(text: String, private var component: JComponent) : BorderLayoutPanel() { private class HideableSection(text: String, private var component: JComponent) : BorderLayoutPanel() {
private val titledSeparator = TitledSeparator(text) private val titledSeparator = TitledSeparator(text)
private val contentPanel = borderPanel {
addBorder(JBUI.Borders.emptyLeft(20))
}
private var isExpanded = false private var isExpanded = false
init { init {
titledSeparator.label.cursor = Cursor(Cursor.HAND_CURSOR) titledSeparator.label.cursor = Cursor(Cursor.HAND_CURSOR)
addToTop(titledSeparator)
addToCenter(contentPanel)
updateComponent(component) updateComponent(component)
titledSeparator.addMouseListener(object : MouseAdapter() { titledSeparator.addMouseListener(object : MouseAdapter() {
override fun mouseReleased(e: MouseEvent) = update(!isExpanded) override fun mouseReleased(e: MouseEvent) = update(!isExpanded)
@@ -217,15 +223,14 @@ private class HideableSection(text: String, private var component: JComponent) :
private fun updateComponent(newComponent: JComponent) { private fun updateComponent(newComponent: JComponent) {
component = newComponent component = newComponent
removeAll() contentPanel.removeAll()
addToTop(titledSeparator) contentPanel.addToCenter(newComponent)
addToCenter(newComponent)
update(isExpanded) update(isExpanded)
} }
private fun update(isExpanded: Boolean) { private fun update(isExpanded: Boolean) {
this.isExpanded = isExpanded this.isExpanded = isExpanded
component.isVisible = isExpanded contentPanel.isVisible = isExpanded
titledSeparator.label.icon = if (isExpanded) AllIcons.General.ArrowDown else AllIcons.General.ArrowRight titledSeparator.label.icon = if (isExpanded) AllIcons.General.ArrowDown else AllIcons.General.ArrowRight
} }
} }
@@ -1,6 +1,8 @@
package org.jetbrains.kotlin.tools.projectWizard.wizard.ui.firstStep package org.jetbrains.kotlin.tools.projectWizard.wizard.ui.firstStep
import com.intellij.openapi.util.SystemInfo
import com.intellij.ui.ScrollPaneFactory import com.intellij.ui.ScrollPaneFactory
import com.intellij.ui.components.JBLabel
import com.intellij.util.ui.JBUI import com.intellij.util.ui.JBUI
import com.intellij.util.ui.UIUtil import com.intellij.util.ui.UIUtil
import org.jetbrains.kotlin.tools.projectWizard.core.Context import org.jetbrains.kotlin.tools.projectWizard.core.Context
@@ -71,10 +73,19 @@ class ProjectTemplateSettingComponent(
} }
class TemplateDescriptionComponent : Component() { class TemplateDescriptionComponent : Component() {
private val descriptionLabel = label("") { private val descriptionLabel = JBLabel().apply {
fontColor = UIUtil.FontColor.BRIGHTER
preferredSize = Dimension(preferredSize.width, 45) preferredSize = Dimension(preferredSize.width, 45)
verticalAlignment = SwingConstants.TOP verticalAlignment = SwingConstants.TOP
isFocusable = false
foreground = UIUtil.getContextHelpForeground()
// taken from com.intellij.openapi.ui.panel.ComponentPanelBuilder.createCommentComponent
if (SystemInfo.isMac) {
val font = component.font
val size = font.size2D
val smallFont = font.deriveFont(size - 2.0f)
this.font = smallFont
}
} }
fun setTemplate(template: ProjectTemplate) { fun setTemplate(template: ProjectTemplate) {
@@ -18,12 +18,13 @@ import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import java.awt.Dimension import java.awt.Dimension
import javax.swing.Icon import javax.swing.Icon
import javax.swing.JPanel import javax.swing.JPanel
import kotlin.reflect.KFunction0
class ModuleDependenciesComponent( class ModuleDependenciesComponent(
context: Context context: Context
) : TitledComponent(context) { ) : TitledComponent(context) {
override val title: String = KotlinNewProjectWizardUIBundle.message("module.dependencies.module.dependencies") override val title: String = KotlinNewProjectWizardUIBundle.message("module.dependencies.module.dependencies")
private val dependenciesList = ModuleDependenciesList() private val dependenciesList = ModuleDependenciesList(::possibleDependencies)
override val forceLabelCenteringOffset: Int? = 4 override val forceLabelCenteringOffset: Int? = 4
override val additionalComponentPadding: Int = 1 override val additionalComponentPadding: Int = 1
override val maximumWidth: Int = 500 override val maximumWidth: Int = 500
@@ -102,9 +103,21 @@ private class AddModulesPopUp(
} }
} }
private class ModuleDependenciesList : AbstractSingleSelectableListWithIcon<Module>() { private class ModuleDependenciesList(getDependencies: () -> List<Module>) : AbstractSingleSelectableListWithIcon<Module>() {
init { init {
setEmptyText(KotlinNewProjectWizardUIBundle.message("module.settings.dependencies.empty")) emptyText.apply {
clear()
appendText(KotlinNewProjectWizardUIBundle.message("module.settings.dependencies.empty"))
appendSecondaryText(
KotlinNewProjectWizardUIBundle.message("module.settings.dependencies.empty.suggest.add"),
SimpleTextAttributes.LINK_ATTRIBUTES
) {
AddModulesPopUp.create(
getDependencies(),
::addDependency
).showInCenterOf(this@ModuleDependenciesList)
}
}
} }
override fun ColoredListCellRenderer<Module>.render(value: Module) { override fun ColoredListCellRenderer<Module>.render(value: Module) {
@@ -1,5 +1,6 @@
package org.jetbrains.kotlin.tools.projectWizard.wizard.ui.secondStep package org.jetbrains.kotlin.tools.projectWizard.wizard.ui.secondStep
import com.intellij.ui.components.JBLabel
import com.intellij.ui.components.JBTextField import com.intellij.ui.components.JBTextField
import com.intellij.ui.layout.panel import com.intellij.ui.layout.panel
import com.intellij.util.ui.JBUI import com.intellij.util.ui.JBUI
@@ -131,9 +132,9 @@ private class ModuleTemplateComponent(
}.asSubComponent() }.asSubComponent()
override val forceLabelCenteringOffset: Int? = 4 override val forceLabelCenteringOffset: Int? = 4
private val templateDescriptionLabel = label("") { private val templateDescriptionLabel = JBLabel().apply {
fontColor = UIUtil.FontColor.BRIGHTER foreground = UIUtil.getContextHelpForeground()
addBorder(JBUI.Borders.empty(4, 4)) addBorder(JBUI.Borders.empty(2, 4))
} }
override fun onInit() { override fun onInit() {
@@ -143,6 +144,7 @@ private class ModuleTemplateComponent(
private fun changeTemplateDescription(template: Template?) { private fun changeTemplateDescription(template: Template?) {
templateDescriptionLabel.text = template?.description templateDescriptionLabel.text = template?.description
templateDescriptionLabel.isVisible = template?.description != null
} }
override val component = borderPanel { override val component = borderPanel {
@@ -1,14 +0,0 @@
package org.jetbrains.kotlin.tools.projectWizard.wizard.ui.secondStep
import org.jetbrains.kotlin.tools.projectWizard.wizard.KotlinNewProjectWizardUIBundle
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.Component
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.PanelWithStatusText
import java.awt.BorderLayout
class NothingSelectedComponent : Component() {
override val component = PanelWithStatusText(
BorderLayout(),
KotlinNewProjectWizardUIBundle.message("error.nothing.selected"),
isStatusTextVisible = true
)
}
@@ -7,6 +7,7 @@ import org.jetbrains.kotlin.tools.projectWizard.core.entity.ValidationResult
import org.jetbrains.kotlin.tools.projectWizard.settings.DisplayableSettingItem import org.jetbrains.kotlin.tools.projectWizard.settings.DisplayableSettingItem
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.Module import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.Module
import org.jetbrains.kotlin.tools.projectWizard.wizard.IdeWizard import org.jetbrains.kotlin.tools.projectWizard.wizard.IdeWizard
import org.jetbrains.kotlin.tools.projectWizard.wizard.KotlinNewProjectWizardUIBundle
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.* import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.*
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.secondStep.modulesEditor.ModulesEditorComponent import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.secondStep.modulesEditor.ModulesEditorComponent
import java.awt.BorderLayout import java.awt.BorderLayout
@@ -64,10 +65,14 @@ class ModuleSettingsSubStep(
) : SubStep(wizard.context) { ) : SubStep(wizard.context) {
private val moduleSettingsComponent = private val moduleSettingsComponent =
ModuleSettingsComponent(wizard.context, uiEditorUsagesStats).asSubComponent() ModuleSettingsComponent(wizard.context, uiEditorUsagesStats).asSubComponent()
private val nothingSelectedComponent = NothingSelectedComponent().asSubComponent() private val nothingSelected = PanelWithStatusText(
BorderLayout(),
KotlinNewProjectWizardUIBundle.message("error.nothing.selected"),
isStatusTextVisible = true
)
private val panel = customPanel { private val panel = customPanel {
add(nothingSelectedComponent.component, BorderLayout.CENTER) add(nothingSelected, BorderLayout.CENTER)
} }
var selectedNode: DisplayableSettingItem? = null var selectedNode: DisplayableSettingItem? = null
@@ -80,10 +85,10 @@ class ModuleSettingsSubStep(
private fun changeComponent() { private fun changeComponent() {
panel.removeAll() panel.removeAll()
val component = when (selectedNode) { val component = when (selectedNode) {
is Module -> moduleSettingsComponent is Module -> moduleSettingsComponent.component
else -> nothingSelectedComponent else -> nothingSelected
} }
panel.add(component.component, BorderLayout.CENTER) panel.add(component, BorderLayout.CENTER)
panel.updateUI() panel.updateUI()
} }
@@ -56,6 +56,9 @@ class ModulesEditorComponent(
override fun onInit() { override fun onInit() {
super.onInit() super.onInit()
updateModel() updateModel()
if (editable) {
value?.firstOrNull()?.let(tree::selectModule)
}
} }
fun updateModel() { fun updateModel() {
@@ -67,7 +67,7 @@ class ModulesEditorToolbarDecorator(
null -> "" null -> ""
} }
text = KotlinNewProjectWizardUIBundle.message("editor.modules.add", moduleKindTextToAdd) text = KotlinNewProjectWizardUIBundle.message("editor.modules.add", moduleKindTextToAdd.capitalize())
} }
event.presentation.isEnabled event.presentation.isEnabled
} }
@@ -77,12 +77,14 @@ class ModulesEditorToolbarDecorator(
if (Messages.showOkCancelDialog( if (Messages.showOkCancelDialog(
tree, tree,
buildString { buildString {
appendln(KotlinNewProjectWizardUIBundle.message("editor.modules.remove.selected.module", moduleKindText)) val moduleName = selectedModule?.name!!
appendln(KotlinNewProjectWizardUIBundle.message("editor.modules.remove.selected.module", moduleName))
if (tree.selectedSettingItem.safeAs<Module>()?.kind != ModuleKind.target) { if (tree.selectedSettingItem.safeAs<Module>()?.kind != ModuleKind.target) {
appendln(KotlinNewProjectWizardUIBundle.message("editor.modules.remove.selected.submodules")) appendln(KotlinNewProjectWizardUIBundle.message("editor.modules.remove.selected.module", moduleName))
} else {
appendln(KotlinNewProjectWizardUIBundle.message("editor.modules.remove.selected.target", moduleName))
} }
appendln() appendln()
appendln(KotlinNewProjectWizardUIBundle.message("editor.modules.remove.selected.no.undone"))
}, },
KotlinNewProjectWizardUIBundle.message("editor.modules.remove.selected.question", moduleKindText), KotlinNewProjectWizardUIBundle.message("editor.modules.remove.selected.question", moduleKindText),
KotlinNewProjectWizardUIBundle.message("editor.modules.remove.selected.remove"), KotlinNewProjectWizardUIBundle.message("editor.modules.remove.selected.remove"),
@@ -98,7 +100,7 @@ class ModulesEditorToolbarDecorator(
isEnabled = tree.selectedSettingItem is Module isEnabled = tree.selectedSettingItem is Module
text = KotlinNewProjectWizardUIBundle.message( text = KotlinNewProjectWizardUIBundle.message(
"editor.modules.remove.tooltip", "editor.modules.remove.tooltip",
selectedModuleKindText?.let { " $it" }.orEmpty() selectedModuleKindText?.let { " ${it.capitalize()}" }.orEmpty()
) )
} }
event.presentation.isEnabled event.presentation.isEnabled
@@ -108,8 +110,11 @@ class ModulesEditorToolbarDecorator(
setMoveUpAction(null) setMoveUpAction(null)
} }
private val selectedModule
get() = tree.selectedSettingItem.safeAs<Module>()
private val selectedModuleKindText private val selectedModuleKindText
get() = tree.selectedSettingItem.safeAs<Module>()?.kindText get() = selectedModule?.kindText
fun createToolPanel(): JComponent = toolbarDecorator fun createToolPanel(): JComponent = toolbarDecorator
.createPanelWithPopupHandler(tree) .createPanelWithPopupHandler(tree)
@@ -80,7 +80,7 @@ open class TitledComponentsList(
var lastLabel: SpringLayout.Constraints? = null var lastLabel: SpringLayout.Constraints? = null
var lastComponent: SpringLayout.Constraints? = null var lastComponent: SpringLayout.Constraints? = null
for (data in componentsWithLabels) { for ((index, data) in componentsWithLabels.withIndex()) {
val (label, component) = data val (label, component) = data
label.x = xPanelPadding.asSpring() label.x = xPanelPadding.asSpring()
component.x = label[SpringLayout.EAST] + xGap component.x = label[SpringLayout.EAST] + xGap
@@ -99,7 +99,7 @@ open class TitledComponentsList(
} }
if (stretchY) { if (stretchY) {
constraints()[SpringLayout.SOUTH] = lastComponent!![SpringLayout.SOUTH] + yGap constraints()[SpringLayout.SOUTH] = lastComponent!![SpringLayout.SOUTH]
} }
} }
@@ -1,6 +1,6 @@
buildsystem.type.gradle.groovy=Gradle Groovy buildsystem.type.gradle.groovy=Gradle Groovy
buildsystem.type.gradle.kotlin=Gradle Kotlin buildsystem.type.gradle.kotlin=Gradle Kotlin
buildsystem.type.intellij=IntelliJ buildsystem.type.intellij=IntelliJ build system
buildsystem.type.maven=Maven buildsystem.type.maven=Maven
error.template.not.found=Template with an id {0} is not found error.template.not.found=Template with an id {0} is not found
@@ -21,7 +21,7 @@ module.kind.module=Module
module.kind.mpp.module=MPP Module module.kind.mpp.module=MPP Module
module.kind.target=Target module.kind.target=Target
plugin.buildsystem.setting.type=Build System plugin.buildsystem.setting.type=Build system
plugin.buildsystem.setting.type.error.wrong.project.kind={0} cannot be generated using {1} plugin.buildsystem.setting.type.error.wrong.project.kind={0} cannot be generated using {1}
plugin.kotlin.downloading.kotlin.versions=Downloading list of Kotlin versions plugin.kotlin.downloading.kotlin.versions=Downloading list of Kotlin versions
@@ -47,7 +47,7 @@ plugin.structure.setting.version=Version
plugin.android.setting.sdk=Android SDK plugin.android.setting.sdk=Android SDK
validation.should.not.be.blank={0} should not be blank validation.should.not.be.blank=Specify {0}
validation.identifier={0} should consist only of letters, digits{1} validation.identifier={0} should consist only of letters, digits{1}
validation.identifier.additional.symbols=, and symbols: {0} validation.identifier.additional.symbols=, and symbols: {0}
validation.file.should.exists=File for {0} should exists validation.file.should.exists=File for {0} should exists
@@ -69,14 +69,14 @@ module.name.with.name=Module name {0}
module.configurator.js=JS for Browser module.configurator.js=JS for Browser
module.configurator.android=Android module.configurator.android=Android
module.configurator.android.setting.android.plugin=Android Plugin module.configurator.android.setting.android.plugin=Android plugin
module.configurator.android.setting.android.plugin.application=Android Application module.configurator.android.setting.android.plugin.application=Android Application
module.configurator.android.setting.android.plugin.library=Android module.configurator.android.setting.android.plugin.library=Android
module.configurator.common=Common module.configurator.common=Common
module.configurator.jvm=JVM module.configurator.jvm=JVM
module.configurator.jvm.setting.target.jvm.version=Target JVM Version module.configurator.jvm.setting.target.jvm.version=Target JVM version
module.configurator.jvm.setting.java.support=Java language support module.configurator.jvm.setting.java.support=Java language support
module.configurator.mpp=Multiplatform module.configurator.mpp=Multiplatform
@@ -86,40 +86,40 @@ module.configurator.ios.requires.xcode=Requires Xcode
module.configurator.js.browser=Browser module.configurator.js.browser=Browser
module.configurator.js.node=Node.js module.configurator.js.node=Node.js
module.configurator.tests.setting.framework=Test Framework module.configurator.tests.setting.framework=Test framework
module.configurator.tests.setting.framework.junit4=JUnit 4 module.configurator.tests.setting.framework.junit4=JUnit 4
module.configurator.tests.setting.framework.junit5=JUnit 5 module.configurator.tests.setting.framework.junit5=JUnit 5
module.configurator.tests.setting.framework.test.ng=Test NG module.configurator.tests.setting.framework.test.ng=TestNG
module.configurator.tests.setting.framework.js=JavaScript module.configurator.tests.setting.framework.js=JavaScript
module.configurator.tests.setting.framework.common=common module.configurator.tests.setting.framework.common=common
module.configurator.native.for.current.system=Your system module.configurator.native.for.current.system=Your system
project.template.empty.singleplatform.title=Backend Application project.template.empty.singleplatform.title=Backend Application
project.template.empty.singleplatform.description=Create a backend application with Kotlin/JVM. project.template.empty.singleplatform.description=Backend application with Kotlin/JVM.
project.template.empty.mpp.title=Multiplatform Application project.template.empty.mpp.title=Multiplatform Application
project.template.empty.mpp.description=Create applications for different platforms that support sharing common code. project.template.empty.mpp.description=Applications for different platforms that support sharing common code.
project.template.empty.jvm.console.title=Console Application project.template.empty.jvm.console.title=Console Application
project.template.empty.jvm.console.description=Create a console application with Kotlin/JVM. Use it for prototyping or testing purposes. project.template.empty.jvm.console.description=Console application with Kotlin/JVM. Use it for prototyping or testing purposes.
project.template.mpp.lib.title=Multiplatform Library project.template.mpp.lib.title=Multiplatform Library
project.template.mpp.lib.description=Create a library for sharing common code among different platforms. project.template.mpp.lib.description=Library for sharing common code among different platforms.
project.template.full.stack.title=Full-Stack Web Application project.template.full.stack.title=Full-Stack Web Application
project.template.full.stack.description=Create a fully-functional web application using Kotlin/JS for the frontend and Kotlin/JVM for the backend. project.template.full.stack.description=Fully-functional web application using Kotlin/JS for the frontend and Kotlin/JVM for the backend.
project.template.native.console.title=Native Application project.template.native.console.title=Native Application
project.template.native.console.description=Create an application with Kotlin/Native that works as a standalone application under a specific platform. project.template.native.console.description=Application with Kotlin/Native that works as a standalone application under a specific platform.
project.template.frontend.title=Frontend Application project.template.frontend.title=Frontend Application
project.template.frontend.description=Create a frontend application with Kotlin/JS if you already have a backend. project.template.frontend.description=Frontend application with Kotlin/JS if you already have a backend.
project.template.mpp.mobile.title=Multiplatform Mobile Application project.template.mpp.mobile.title=Multiplatform Mobile Application
project.template.mpp.mobile.description=Create mobile applications for iOS and Android with Kotlin Multiplatform Mobile, which supports sharing common code between platforms. project.template.mpp.mobile.description=Mobile applications for iOS and Android with Kotlin Multiplatform Mobile, which supports sharing common code between platforms.
project.template.mpp.mobile.lib.title=Multiplatform Mobile Library project.template.mpp.mobile.lib.title=Multiplatform Mobile Library
project.template.mpp.mobile.lib.description=Create a library that supports sharing code between iOS and Android. project.template.mpp.mobile.lib.description=Library that supports sharing code between iOS and Android.
module.template.console.jvm.title=Console Application module.template.console.jvm.title=Console Application