Merge pull request #38 from marhali/rc/1.4.0

Rc/1.4.0
This commit is contained in:
Marcel 2021-07-20 16:11:00 +02:00 committed by GitHub
commit c1ad9602d8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
47 changed files with 423 additions and 125 deletions

View File

@ -3,13 +3,26 @@
# easy-i18n Changelog # easy-i18n Changelog
## [Unreleased] ## [Unreleased]
### THANKS FOR OVER 1000 DOWNLOADS SO FAR!
### Added
- Basic support for json array values
- Settings option to opt-out code assistance inside editor
- Support key completion and annotation for Kotlin language
- Example locale files for all configuration options
- Donation links on GitHub to support development
### Changed
- Update dependencies
- Migrate gradle build script
## [1.3.0] ## [1.3.0]
### Added ### Added
- Scroll to created / edited translation inside Tree-/Table-View - Scroll to created / edited translation inside Tree-/Table-View
- Support for working with multiple projects at once - Support for working with multiple projects at once
### Changed ### Changed
- Updated dependencies - Update dependencies
- Load translations even if ui tool window is not opened - Load translations even if ui tool window is not opened
### Fixed ### Fixed
@ -28,7 +41,7 @@
- Support for IntelliJ 2021.1 - Support for IntelliJ 2021.1
### Changed ### Changed
- Updated dependencies - Update dependencies
### Fixed ### Fixed
- Exception during i18n key completion / annotation - Exception during i18n key completion / annotation

View File

@ -3,6 +3,7 @@
![Build](https://github.com/marhali/easy-i18n/workflows/Build/badge.svg) ![Build](https://github.com/marhali/easy-i18n/workflows/Build/badge.svg)
[![Version](https://img.shields.io/jetbrains/plugin/v/16316.svg)](https://plugins.jetbrains.com/plugin/16316) [![Version](https://img.shields.io/jetbrains/plugin/v/16316.svg)](https://plugins.jetbrains.com/plugin/16316)
[![Downloads](https://img.shields.io/jetbrains/plugin/d/16316.svg)](https://plugins.jetbrains.com/plugin/16316) [![Downloads](https://img.shields.io/jetbrains/plugin/d/16316.svg)](https://plugins.jetbrains.com/plugin/16316)
[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://paypal.me/marhalide)
<!-- Plugin description --> <!-- Plugin description -->
This is an easy plugin to manage internationalization for JSON or Resource-Bundle(Properties) based locale files. This is an easy plugin to manage internationalization for JSON or Resource-Bundle(Properties) based locale files.
@ -48,6 +49,11 @@ Most common use case is for translating Webapps or simple Java Applications. Tra
- Select the created directory (optional: define the preferred locale to view) and press Ok - Select the created directory (optional: define the preferred locale to view) and press Ok
- Translations can now be created / edited or deleted - Translations can now be created / edited or deleted
Examples for the configuration can be found in the [/example](https://github.com/marhali/easy-i18n/tree/main/example) folder.
## Donation
If the project helps you to reduce development time, you can give me a [cup of coffee](https://paypal.me/marhalide) :)
--- ---
Plugin based on the [IntelliJ Platform Plugin Template][template]. Plugin based on the [IntelliJ Platform Plugin Template][template].

View File

@ -1,5 +1,4 @@
import io.gitlab.arturbosch.detekt.Detekt import io.gitlab.arturbosch.detekt.Detekt
import org.jetbrains.changelog.closure
import org.jetbrains.changelog.markdownToHTML import org.jetbrains.changelog.markdownToHTML
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
@ -11,7 +10,7 @@ plugins {
// Kotlin support // Kotlin support
id("org.jetbrains.kotlin.jvm") version "1.5.10" id("org.jetbrains.kotlin.jvm") version "1.5.10"
// gradle-intellij-plugin - read more: https://github.com/JetBrains/gradle-intellij-plugin // gradle-intellij-plugin - read more: https://github.com/JetBrains/gradle-intellij-plugin
id("org.jetbrains.intellij") version "0.7.3" id("org.jetbrains.intellij") version "1.0"
// gradle-changelog-plugin - read more: https://github.com/JetBrains/gradle-changelog-plugin // gradle-changelog-plugin - read more: https://github.com/JetBrains/gradle-changelog-plugin
id("org.jetbrains.changelog") version "1.1.2" id("org.jetbrains.changelog") version "1.1.2"
// detekt linter - read more: https://detekt.github.io/detekt/gradle.html // detekt linter - read more: https://detekt.github.io/detekt/gradle.html
@ -26,7 +25,6 @@ version = properties("pluginVersion")
// Configure project's dependencies // Configure project's dependencies
repositories { repositories {
mavenCentral() mavenCentral()
jcenter()
} }
dependencies { dependencies {
detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:1.17.1") detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:1.17.1")
@ -35,14 +33,14 @@ dependencies {
// Configure gradle-intellij-plugin plugin. // Configure gradle-intellij-plugin plugin.
// Read more: https://github.com/JetBrains/gradle-intellij-plugin // Read more: https://github.com/JetBrains/gradle-intellij-plugin
intellij { intellij {
pluginName = properties("pluginName") pluginName.set(properties("pluginName"))
version = properties("platformVersion") version.set(properties("platformVersion"))
type = properties("platformType") type.set(properties("platformType"))
downloadSources = properties("platformDownloadSources").toBoolean() downloadSources.set(properties("platformDownloadSources").toBoolean())
updateSinceUntilBuild = true updateSinceUntilBuild.set(true)
// Plugin Dependencies. Uses `platformPlugins` property from the gradle.properties file. // Plugin Dependencies. Uses `platformPlugins` property from the gradle.properties file.
setPlugins(*properties("platformPlugins").split(',').map(String::trim).filter(String::isNotEmpty).toTypedArray()) plugins.set(properties("platformPlugins").split(',').map(String::trim).filter(String::isNotEmpty))
} }
// Configure gradle-changelog-plugin plugin. // Configure gradle-changelog-plugin plugin.
@ -80,43 +78,37 @@ tasks {
} }
patchPluginXml { patchPluginXml {
version(properties("pluginVersion")) version.set(properties("pluginVersion"))
sinceBuild(properties("pluginSinceBuild")) sinceBuild.set(properties("pluginSinceBuild"))
untilBuild(properties("pluginUntilBuild")) untilBuild.set(properties("pluginUntilBuild"))
// Extract the <!-- Plugin description --> section from README.md and provide for the plugin's manifest // Extract the <!-- Plugin description --> section from README.md and provide for the plugin's manifest
pluginDescription( pluginDescription.set(
closure { File(projectDir, "README.md").readText().lines().run {
File("./README.md").readText().lines().run { val start = "<!-- Plugin description -->"
val start = "<!-- Plugin description -->" val end = "<!-- Plugin description end -->"
val end = "<!-- Plugin description end -->"
if (!containsAll(listOf(start, end))) { if (!containsAll(listOf(start, end))) {
throw GradleException("Plugin description section not found in README.md:\n$start ... $end") throw GradleException("Plugin description section not found in README.md:\n$start ... $end")
} }
subList(indexOf(start) + 1, indexOf(end)) subList(indexOf(start) + 1, indexOf(end))
}.joinToString("\n").run { markdownToHTML(this) } }.joinToString("\n").run { markdownToHTML(this) }
}
) )
// Get the latest available change notes from the changelog file // Get the latest available change notes from the changelog file
changeNotes( changeNotes.set(provider { changelog.getLatest().toHTML() })
closure {
changelog.getLatest().toHTML()
}
)
} }
runPluginVerifier { runPluginVerifier {
ideVersions(properties("pluginVerifierIdeVersions")) ideVersions.set(properties("pluginVerifierIdeVersions").split(',').map(String::trim).filter(String::isNotEmpty))
} }
publishPlugin { publishPlugin {
dependsOn("patchChangelog") dependsOn("patchChangelog")
token(System.getenv("PUBLISH_TOKEN")) token.set(System.getenv("PUBLISH_TOKEN"))
// pluginVersion is based on the SemVer (https://semver.org) and supports pre-release labels, like 2.1.7-alpha.3 // pluginVersion is based on the SemVer (https://semver.org) and supports pre-release labels, like 2.1.7-alpha.3
// Specify pre-release label to publish the plugin in a custom Release Channel automatically. Read more: // Specify pre-release label to publish the plugin in a custom Release Channel automatically. Read more:
// https://plugins.jetbrains.com/docs/intellij/deployment.html#specifying-a-release-channel // https://plugins.jetbrains.com/docs/intellij/deployment.html#specifying-a-release-channel
channels(properties("pluginVersion").split('-').getOrElse(1) { "default" }.split('.').first()) channels.set(listOf(properties("pluginVersion").split('-').getOrElse(1) { "default" }.split('.').first()))
} }
} }

View File

@ -0,0 +1,26 @@
{
"alpha": {
"first": "Beispiel Übersetzung",
"second": "Andere Übersetzung"
},
"beta": {
"title": "Ein Titel",
"nested": {
"title": "Ein verschachtelter Titel"
}
},
"gamma": {
"title": "Gamma Titel",
"array": {
"simple": [
"Erstes Element",
"Zweites Element"
],
"escaped": [
"Erstes;Element",
"Zweites Element",
"Drittes;Element"
]
}
}
}

View File

@ -0,0 +1,26 @@
{
"alpha": {
"first": "example translation",
"second": "another translation"
},
"beta": {
"title": "some title",
"nested": {
"title": "some nested title"
}
},
"gamma": {
"title": "gamma title",
"array": {
"simple": [
"first element",
"second element"
],
"escaped": [
"first;element",
"second element",
"third;element"
]
}
}
}

View File

@ -0,0 +1,5 @@
{
"subscription": "Abonnement",
"support": "Unterstützung",
"delete": "Löschen"
}

View File

@ -0,0 +1,10 @@
{
"title": [
"Ein",
"array",
"Titel"
],
"login": "Einloggen",
"logout": "Ausloggen",
"register": "Registrieren"
}

View File

@ -0,0 +1,10 @@
{
"username": "Benutzername",
"email": "Email-Adresse",
"address": {
"zip": "Postleitzahl",
"city": "Ort",
"street": "Straße",
"number": "Hausnummer"
}
}

View File

@ -0,0 +1,5 @@
{
"subscription": "Subscription",
"support": "Support",
"delete": "Delete"
}

View File

@ -0,0 +1,10 @@
{
"title": [
"Some",
"array",
"title"
],
"login": "Login",
"logout": "Logout",
"register": "Register"
}

View File

@ -0,0 +1,10 @@
{
"username": "Username",
"email": "Email Address",
"address": {
"zip": "ZIP code",
"city": "City",
"street": "Street",
"number": "House number"
}
}

View File

@ -0,0 +1,6 @@
account.subscription=Abonnement
auth.login=Einloggen
auth.logout=Ausloggen
auth.register=Registrieren
user.email=Email-Adresse
user.username=Benutzername

View File

@ -0,0 +1,6 @@
account.subscription=Subscription
auth.login=Login
auth.logout=Logout
auth.register=Register
user.email=Email Address
user.username=Username

View File

@ -3,19 +3,19 @@
pluginGroup = de.marhali.easyi18n pluginGroup = de.marhali.easyi18n
pluginName = easy-i18n pluginName = easy-i18n
pluginVersion = 1.3.0 pluginVersion = 1.4.0
pluginSinceBuild = 202 pluginSinceBuild = 202
pluginUntilBuild = 211.* pluginUntilBuild = 211.*
# Plugin Verifier integration -> https://github.com/JetBrains/gradle-intellij-plugin#plugin-verifier-dsl # Plugin Verifier integration -> https://github.com/JetBrains/gradle-intellij-plugin#plugin-verifier-dsl
# See https://jb.gg/intellij-platform-builds-list for available build versions # See https://jb.gg/intellij-platform-builds-list for available build versions
pluginVerifierIdeVersions = 2020.2.4, 2020.3.2, 2021.1 pluginVerifierIdeVersions = 2020.2.4, 2020.3.4, 2021.1.1
platformType = IC platformType = IC
platformVersion = 2021.1 platformVersion = 2021.1.3
platformDownloadSources = true platformDownloadSources = true
# Plugin Dependencies -> https://plugins.jetbrains.com/docs/intellij/plugin-dependencies.html # Plugin Dependencies -> https://plugins.jetbrains.com/docs/intellij/plugin-dependencies.html
# Example: platformPlugins = com.intellij.java, com.jetbrains.php:203.4449.22 # Example: platformPlugins = com.intellij.java, com.jetbrains.php:203.4449.22
platformPlugins = platformPlugins = org.jetbrains.kotlin
# Opt-out flag for bundling Kotlin standard library. # Opt-out flag for bundling Kotlin standard library.
# See https://kotlinlang.org/docs/reference/using-gradle.html#dependency-on-the-standard-library for details. # See https://kotlinlang.org/docs/reference/using-gradle.html#dependency-on-the-standard-library for details.

View File

@ -9,9 +9,9 @@ import com.intellij.ui.content.ContentFactory;
import de.marhali.easyi18n.service.DataStore; import de.marhali.easyi18n.service.DataStore;
import de.marhali.easyi18n.service.WindowManager; import de.marhali.easyi18n.service.WindowManager;
import de.marhali.easyi18n.ui.action.*; import de.marhali.easyi18n.action.*;
import de.marhali.easyi18n.ui.tabs.TableView; import de.marhali.easyi18n.tabs.TableView;
import de.marhali.easyi18n.ui.tabs.TreeView; import de.marhali.easyi18n.tabs.TreeView;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;

View File

@ -1,11 +1,11 @@
package de.marhali.easyi18n.ui.action; package de.marhali.easyi18n.action;
import com.intellij.icons.AllIcons; import com.intellij.icons.AllIcons;
import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.AnActionEvent;
import de.marhali.easyi18n.service.WindowManager; import de.marhali.easyi18n.service.WindowManager;
import de.marhali.easyi18n.ui.dialog.AddDialog; import de.marhali.easyi18n.dialog.AddDialog;
import de.marhali.easyi18n.util.TreeUtil; import de.marhali.easyi18n.util.TreeUtil;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;

View File

@ -1,4 +1,4 @@
package de.marhali.easyi18n.ui.action; package de.marhali.easyi18n.action;
import com.intellij.icons.AllIcons; import com.intellij.icons.AllIcons;
import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnAction;

View File

@ -1,4 +1,4 @@
package de.marhali.easyi18n.ui.action; package de.marhali.easyi18n.action;
import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.AnActionEvent;

View File

@ -1,9 +1,9 @@
package de.marhali.easyi18n.ui.action; package de.marhali.easyi18n.action;
import com.intellij.icons.AllIcons; import com.intellij.icons.AllIcons;
import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.AnActionEvent;
import de.marhali.easyi18n.ui.dialog.SettingsDialog; import de.marhali.easyi18n.dialog.SettingsDialog;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.ResourceBundle; import java.util.ResourceBundle;

View File

@ -1,4 +1,4 @@
package de.marhali.easyi18n.ui.action.treeview; package de.marhali.easyi18n.action.treeview;
import com.intellij.icons.AllIcons; import com.intellij.icons.AllIcons;
import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnAction;

View File

@ -1,4 +1,4 @@
package de.marhali.easyi18n.ui.action.treeview; package de.marhali.easyi18n.action.treeview;
import com.intellij.icons.AllIcons; import com.intellij.icons.AllIcons;
import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnAction;

View File

@ -1,4 +1,4 @@
package de.marhali.easyi18n.ui.dialog; package de.marhali.easyi18n.dialog;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogBuilder; import com.intellij.openapi.ui.DialogBuilder;

View File

@ -1,4 +1,4 @@
package de.marhali.easyi18n.ui.dialog; package de.marhali.easyi18n.dialog;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogBuilder; import com.intellij.openapi.ui.DialogBuilder;
@ -10,7 +10,7 @@ import de.marhali.easyi18n.service.DataStore;
import de.marhali.easyi18n.model.KeyedTranslation; import de.marhali.easyi18n.model.KeyedTranslation;
import de.marhali.easyi18n.model.TranslationDelete; import de.marhali.easyi18n.model.TranslationDelete;
import de.marhali.easyi18n.model.TranslationUpdate; import de.marhali.easyi18n.model.TranslationUpdate;
import de.marhali.easyi18n.ui.dialog.descriptor.DeleteActionDescriptor; import de.marhali.easyi18n.dialog.descriptor.DeleteActionDescriptor;
import javax.swing.*; import javax.swing.*;
import javax.swing.border.EtchedBorder; import javax.swing.border.EtchedBorder;

View File

@ -1,10 +1,11 @@
package de.marhali.easyi18n.ui.dialog; package de.marhali.easyi18n.dialog;
import com.intellij.openapi.fileChooser.FileChooserDescriptor; import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogBuilder; import com.intellij.openapi.ui.DialogBuilder;
import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.TextFieldWithBrowseButton; import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import com.intellij.ui.components.JBCheckBox;
import com.intellij.ui.components.JBLabel; import com.intellij.ui.components.JBLabel;
import com.intellij.ui.components.JBTextField; import com.intellij.ui.components.JBTextField;
@ -26,6 +27,7 @@ public class SettingsDialog {
private TextFieldWithBrowseButton pathText; private TextFieldWithBrowseButton pathText;
private JBTextField filePatternText; private JBTextField filePatternText;
private JBTextField previewText; private JBTextField previewText;
private JBCheckBox codeAssistanceCheckbox;
public SettingsDialog(Project project) { public SettingsDialog(Project project) {
this.project = project; this.project = project;
@ -35,18 +37,20 @@ public class SettingsDialog {
String localesPath = SettingsService.getInstance(project).getState().getLocalesPath(); String localesPath = SettingsService.getInstance(project).getState().getLocalesPath();
String filePattern = SettingsService.getInstance(project).getState().getFilePattern(); String filePattern = SettingsService.getInstance(project).getState().getFilePattern();
String previewLocale = SettingsService.getInstance(project).getState().getPreviewLocale(); String previewLocale = SettingsService.getInstance(project).getState().getPreviewLocale();
boolean codeAssistance = SettingsService.getInstance(project).getState().isCodeAssistance();
if(prepare(localesPath, filePattern, previewLocale).show() == DialogWrapper.OK_EXIT_CODE) { // Save changes if(prepare(localesPath, filePattern, previewLocale, codeAssistance).show() == DialogWrapper.OK_EXIT_CODE) { // Save changes
SettingsService.getInstance(project).getState().setLocalesPath(pathText.getText()); SettingsService.getInstance(project).getState().setLocalesPath(pathText.getText());
SettingsService.getInstance(project).getState().setFilePattern(filePatternText.getText()); SettingsService.getInstance(project).getState().setFilePattern(filePatternText.getText());
SettingsService.getInstance(project).getState().setPreviewLocale(previewText.getText()); SettingsService.getInstance(project).getState().setPreviewLocale(previewText.getText());
SettingsService.getInstance(project).getState().setCodeAssistance(codeAssistanceCheckbox.isSelected());
// Reload instance // Reload instance
DataStore.getInstance(project).reloadFromDisk(); DataStore.getInstance(project).reloadFromDisk();
} }
} }
private DialogBuilder prepare(String localesPath, String filePattern, String previewLocale) { private DialogBuilder prepare(String localesPath, String filePattern, String previewLocale, boolean codeAssistance) {
JPanel rootPanel = new JPanel(new GridLayout(0, 1, 2, 2)); JPanel rootPanel = new JPanel(new GridLayout(0, 1, 2, 2));
JBLabel pathLabel = new JBLabel(ResourceBundle.getBundle("messages").getString("settings.path.text")); JBLabel pathLabel = new JBLabel(ResourceBundle.getBundle("messages").getString("settings.path.text"));
@ -73,6 +77,11 @@ public class SettingsDialog {
rootPanel.add(previewLabel); rootPanel.add(previewLabel);
rootPanel.add(previewText); rootPanel.add(previewText);
codeAssistanceCheckbox = new JBCheckBox(ResourceBundle.getBundle("messages").getString("settings.editor.assistance"));
codeAssistanceCheckbox.setSelected(codeAssistance);
rootPanel.add(codeAssistanceCheckbox);
DialogBuilder builder = new DialogBuilder(); DialogBuilder builder = new DialogBuilder();
builder.setTitle(ResourceBundle.getBundle("messages").getString("action.settings")); builder.setTitle(ResourceBundle.getBundle("messages").getString("action.settings"));
builder.removeAllActions(); builder.removeAllActions();

View File

@ -1,4 +1,4 @@
package de.marhali.easyi18n.ui.dialog.descriptor; package de.marhali.easyi18n.dialog.descriptor;
import com.intellij.openapi.ui.DialogBuilder; import com.intellij.openapi.ui.DialogBuilder;
import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.DialogWrapper;

View File

@ -1,11 +1,8 @@
package de.marhali.easyi18n.ui.editor; package de.marhali.easyi18n.editor;
import com.intellij.lang.annotation.AnnotationHolder; import com.intellij.lang.annotation.AnnotationHolder;
import com.intellij.lang.annotation.Annotator;
import com.intellij.lang.annotation.HighlightSeverity; import com.intellij.lang.annotation.HighlightSeverity;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiLiteralValue;
import de.marhali.easyi18n.model.LocalizedNode; import de.marhali.easyi18n.model.LocalizedNode;
import de.marhali.easyi18n.service.DataStore; import de.marhali.easyi18n.service.DataStore;
@ -14,28 +11,25 @@ import de.marhali.easyi18n.service.SettingsService;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
/** /**
* Translation key annotator. * Superclass for managing key annotations.
* @author marhali * @author marhali
*/ */
public class I18nKeyAnnotator implements Annotator { public class KeyAnnotator {
@Override /**
public void annotate(@NotNull PsiElement element, @NotNull AnnotationHolder holder) { * Adds annotations for i18n keys with content preview for preferred locale.
if(!(element instanceof PsiLiteralValue)) { * @param key I18n key extracted by psi element
* @param project Project instance
* @param holder Annotation holder
*/
protected void annotate(@NotNull String key, @NotNull Project project, @NotNull AnnotationHolder holder) {
// Do not annotate keys if service is disabled
if(!SettingsService.getInstance(project).getState().isCodeAssistance()) {
return; return;
} }
PsiLiteralValue literalValue = (PsiLiteralValue) element;
String value = literalValue.getValue() instanceof String ? (String) literalValue.getValue() : null;
if(value == null) {
return;
}
Project project = element.getProject();
String previewLocale = SettingsService.getInstance(project).getState().getPreviewLocale(); String previewLocale = SettingsService.getInstance(project).getState().getPreviewLocale();
LocalizedNode node = DataStore.getInstance(project).getTranslations().getNode(key);
LocalizedNode node = DataStore.getInstance(project).getTranslations().getNode(value);
if(node == null) { // Unknown translation. Just ignore it if(node == null) { // Unknown translation. Just ignore it
return; return;

View File

@ -1,4 +1,4 @@
package de.marhali.easyi18n.ui.editor; package de.marhali.easyi18n.editor;
import com.intellij.codeInsight.completion.CompletionParameters; import com.intellij.codeInsight.completion.CompletionParameters;
import com.intellij.codeInsight.completion.CompletionProvider; import com.intellij.codeInsight.completion.CompletionProvider;
@ -20,11 +20,19 @@ import java.util.List;
* I18n translation key completion provider. * I18n translation key completion provider.
* @author marhali * @author marhali
*/ */
public class I18nCompletionProvider extends CompletionProvider<CompletionParameters> { public class KeyCompletionProvider extends CompletionProvider<CompletionParameters> {
@Override @Override
protected void addCompletions(@NotNull CompletionParameters parameters, @NotNull ProcessingContext context, @NotNull CompletionResultSet result) { protected void addCompletions(@NotNull CompletionParameters parameters,
@NotNull ProcessingContext context, @NotNull CompletionResultSet result) {
Project project = parameters.getOriginalFile().getProject(); Project project = parameters.getOriginalFile().getProject();
// Do not annotate keys if service is disabled
if(!SettingsService.getInstance(project).getState().isCodeAssistance()) {
return;
}
String previewLocale = SettingsService.getInstance(project).getState().getPreviewLocale(); String previewLocale = SettingsService.getInstance(project).getState().getPreviewLocale();
String query = result.getPrefixMatcher().getPrefix(); String query = result.getPrefixMatcher().getPrefix();

View File

@ -0,0 +1,33 @@
package de.marhali.easyi18n.editor.generic;
import com.intellij.lang.annotation.AnnotationHolder;
import com.intellij.lang.annotation.Annotator;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiLiteralValue;
import de.marhali.easyi18n.editor.KeyAnnotator;
import org.jetbrains.annotations.NotNull;
/**
* Translation key annotator for generic languages which support {@link PsiLiteralValue}.
* @author marhali
*/
public class GenericKeyAnnotator extends KeyAnnotator implements Annotator {
@Override
public void annotate(@NotNull PsiElement element, @NotNull AnnotationHolder holder) {
if(!(element instanceof PsiLiteralValue)) {
return;
}
PsiLiteralValue literalValue = (PsiLiteralValue) element;
String value = literalValue.getValue() instanceof String ? (String) literalValue.getValue() : null;
if(value == null) {
return;
}
annotate(value, element.getProject(), holder);
}
}

View File

@ -0,0 +1,19 @@
package de.marhali.easyi18n.editor.generic;
import com.intellij.codeInsight.completion.CompletionContributor;
import com.intellij.codeInsight.completion.CompletionType;
import com.intellij.patterns.*;
import com.intellij.psi.PsiLiteralValue;
import de.marhali.easyi18n.editor.KeyCompletionProvider;
/**
* Translation key completion for generic languages which support {@link PsiLiteralValue}.
* @author marhali
*/
public class GenericKeyCompletionContributor extends CompletionContributor {
public GenericKeyCompletionContributor() {
extend(CompletionType.BASIC, PlatformPatterns.psiElement().inside(PsiLiteralValue.class),
new KeyCompletionProvider());
}
}

View File

@ -0,0 +1,31 @@
package de.marhali.easyi18n.editor.kotlin;
import com.intellij.lang.annotation.AnnotationHolder;
import com.intellij.lang.annotation.Annotator;
import com.intellij.psi.PsiElement;
import de.marhali.easyi18n.editor.KeyAnnotator;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.psi.KtLiteralStringTemplateEntry;
/**
* Kotlin specific translation key annotator
* @author marhali
*/
public class KotlinKeyAnnotator extends KeyAnnotator implements Annotator {
@Override
public void annotate(@NotNull PsiElement element, @NotNull AnnotationHolder holder) {
if(!(element instanceof KtLiteralStringTemplateEntry)) {
return;
}
String value = element.getText();
if(value == null) {
return;
}
annotate(value, element.getProject(), holder);
}
}

View File

@ -0,0 +1,20 @@
package de.marhali.easyi18n.editor.kotlin;
import com.intellij.codeInsight.completion.CompletionContributor;
import com.intellij.codeInsight.completion.CompletionType;
import com.intellij.patterns.PlatformPatterns;
import de.marhali.easyi18n.editor.KeyCompletionProvider;
import org.jetbrains.kotlin.psi.KtLiteralStringTemplateEntry;
/**
* Kotlin specific translation key completion contributor.
* @author marhali
*/
public class KotlinKeyCompletionContributor extends CompletionContributor {
public KotlinKeyCompletionContributor() {
extend(CompletionType.BASIC, PlatformPatterns.psiElement().inside(KtLiteralStringTemplateEntry.class),
new KeyCompletionProvider());
}
}

View File

@ -1,4 +1,4 @@
package de.marhali.easyi18n.ui.listener; package de.marhali.easyi18n.listener;
import java.awt.event.KeyEvent; import java.awt.event.KeyEvent;
import java.awt.event.KeyListener; import java.awt.event.KeyListener;

View File

@ -1,4 +1,4 @@
package de.marhali.easyi18n.ui.listener; package de.marhali.easyi18n.listener;
import java.awt.event.MouseEvent; import java.awt.event.MouseEvent;
import java.awt.event.MouseListener; import java.awt.event.MouseListener;

View File

@ -11,10 +11,12 @@ public class SettingsState {
public static final String DEFAULT_PREVIEW_LOCALE = "en"; public static final String DEFAULT_PREVIEW_LOCALE = "en";
public static final String DEFAULT_FILE_PATTERN = ".*"; public static final String DEFAULT_FILE_PATTERN = ".*";
public static final boolean DEFAULT_CODE_ASSISTANCE = true;
private String localesPath; private String localesPath;
private String filePattern; private String filePattern;
private String previewLocale; private String previewLocale;
private Boolean codeAssistance;
public SettingsState() {} public SettingsState() {}
@ -41,4 +43,12 @@ public class SettingsState {
public void setPreviewLocale(String previewLocale) { public void setPreviewLocale(String previewLocale) {
this.previewLocale = previewLocale; this.previewLocale = previewLocale;
} }
public boolean isCodeAssistance() {
return codeAssistance == null ? DEFAULT_CODE_ASSISTANCE : codeAssistance;
}
public void setCodeAssistance(boolean codeAssistance) {
this.codeAssistance = codeAssistance;
}
} }

View File

@ -1,4 +1,4 @@
package de.marhali.easyi18n.ui.renderer; package de.marhali.easyi18n.renderer;
import com.intellij.ui.JBColor; import com.intellij.ui.JBColor;

View File

@ -1,4 +1,4 @@
package de.marhali.easyi18n.ui.renderer; package de.marhali.easyi18n.renderer;
import com.intellij.ide.util.treeView.NodeRenderer; import com.intellij.ide.util.treeView.NodeRenderer;
import com.intellij.navigation.ItemPresentation; import com.intellij.navigation.ItemPresentation;
@ -7,9 +7,6 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import javax.swing.*; import javax.swing.*;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.TreeCellRenderer;
import java.awt.*;
/** /**
* Similar to {@link NodeRenderer} but will will override {@link #getPresentation(Object)} to * Similar to {@link NodeRenderer} but will will override {@link #getPresentation(Object)} to

View File

@ -2,8 +2,8 @@ package de.marhali.easyi18n.service;
import com.intellij.openapi.wm.ToolWindow; import com.intellij.openapi.wm.ToolWindow;
import de.marhali.easyi18n.ui.tabs.TableView; import de.marhali.easyi18n.tabs.TableView;
import de.marhali.easyi18n.ui.tabs.TreeView; import de.marhali.easyi18n.tabs.TreeView;
public class WindowManager { public class WindowManager {

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="de.marhali.easyi18n.ui.tabs.TableView"> <form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="de.marhali.easyi18n.tabs.TableView">
<grid id="27dc6" binding="rootPanel" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> <grid id="27dc6" binding="rootPanel" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/> <margin top="0" left="0" bottom="0" right="0"/>
<constraints> <constraints>

View File

@ -1,4 +1,4 @@
package de.marhali.easyi18n.ui.tabs; package de.marhali.easyi18n.tabs;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
import com.intellij.ui.components.JBScrollPane; import com.intellij.ui.components.JBScrollPane;
@ -11,10 +11,10 @@ import de.marhali.easyi18n.model.Translations;
import de.marhali.easyi18n.model.KeyedTranslation; import de.marhali.easyi18n.model.KeyedTranslation;
import de.marhali.easyi18n.model.TranslationDelete; import de.marhali.easyi18n.model.TranslationDelete;
import de.marhali.easyi18n.model.table.TableModelTranslator; import de.marhali.easyi18n.model.table.TableModelTranslator;
import de.marhali.easyi18n.ui.dialog.EditDialog; import de.marhali.easyi18n.dialog.EditDialog;
import de.marhali.easyi18n.ui.listener.DeleteKeyListener; import de.marhali.easyi18n.listener.DeleteKeyListener;
import de.marhali.easyi18n.ui.listener.PopupClickListener; import de.marhali.easyi18n.listener.PopupClickListener;
import de.marhali.easyi18n.ui.renderer.TableRenderer; import de.marhali.easyi18n.renderer.TableRenderer;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="de.marhali.easyi18n.ui.tabs.TreeView"> <form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="de.marhali.easyi18n.tabs.TreeView">
<grid id="27dc6" binding="rootPanel" layout-manager="BorderLayout" hgap="0" vgap="0"> <grid id="27dc6" binding="rootPanel" layout-manager="BorderLayout" hgap="0" vgap="0">
<constraints> <constraints>
<xy x="20" y="20" width="500" height="400"/> <xy x="20" y="20" width="500" height="400"/>

View File

@ -1,4 +1,4 @@
package de.marhali.easyi18n.ui.tabs; package de.marhali.easyi18n.tabs;
import com.intellij.ide.projectView.PresentationData; import com.intellij.ide.projectView.PresentationData;
import com.intellij.openapi.actionSystem.ActionManager; import com.intellij.openapi.actionSystem.ActionManager;
@ -14,13 +14,12 @@ import de.marhali.easyi18n.model.Translations;
import de.marhali.easyi18n.model.KeyedTranslation; import de.marhali.easyi18n.model.KeyedTranslation;
import de.marhali.easyi18n.model.TranslationDelete; import de.marhali.easyi18n.model.TranslationDelete;
import de.marhali.easyi18n.model.tree.TreeModelTranslator; import de.marhali.easyi18n.model.tree.TreeModelTranslator;
import de.marhali.easyi18n.ui.action.treeview.CollapseTreeViewAction; import de.marhali.easyi18n.action.treeview.CollapseTreeViewAction;
import de.marhali.easyi18n.ui.action.treeview.ExpandTreeViewAction; import de.marhali.easyi18n.action.treeview.ExpandTreeViewAction;
import de.marhali.easyi18n.ui.dialog.EditDialog; import de.marhali.easyi18n.dialog.EditDialog;
import de.marhali.easyi18n.ui.listener.DeleteKeyListener; import de.marhali.easyi18n.listener.DeleteKeyListener;
import de.marhali.easyi18n.ui.listener.PopupClickListener; import de.marhali.easyi18n.listener.PopupClickListener;
import de.marhali.easyi18n.ui.renderer.TreeRenderer; import de.marhali.easyi18n.renderer.TreeRenderer;
import de.marhali.easyi18n.util.TranslationsUtil;
import de.marhali.easyi18n.util.TreeUtil; import de.marhali.easyi18n.util.TreeUtil;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;

View File

@ -1,18 +0,0 @@
package de.marhali.easyi18n.ui.editor;
import com.intellij.codeInsight.completion.CompletionContributor;
import com.intellij.codeInsight.completion.CompletionType;
import com.intellij.patterns.*;
import com.intellij.psi.PsiLiteralValue;
/**
* Show i18n key completion for literal values.
* @author marhali
*/
public class I18nCompletionContributor extends CompletionContributor {
public I18nCompletionContributor() {
extend(CompletionType.BASIC, PlatformPatterns.psiElement().inside(PsiLiteralValue.class),
new I18nCompletionProvider());
}
}

View File

@ -0,0 +1,51 @@
package de.marhali.easyi18n.util;
import com.google.gson.JsonArray;
import org.apache.commons.lang.StringEscapeUtils;
import java.util.regex.Pattern;
/**
* Utility methods to read and write json arrays.
* @author marhali
*/
public class JsonArrayUtil {
public static String ARRAY_PREFIX = "!arr[";
public static String ARRAY_SUFFIX = "]";
public static char ARRAY_DELIMITER = ';';
public static String read(JsonArray array) {
StringBuilder builder = new StringBuilder(ARRAY_PREFIX);
for(int i = 0; i < array.size(); i++) {
if(i > 0) {
builder.append(ARRAY_DELIMITER);
}
String value = array.get(i).getAsString().replace(";", "\\;");
builder.append(StringUtil.escapeControls(value, true));
}
builder.append(ARRAY_SUFFIX);
return builder.toString();
}
public static JsonArray write(String concat) {
concat = concat.substring(ARRAY_PREFIX.length(), concat.length() - ARRAY_SUFFIX.length());
String regex = "(?<!\\\\)" + Pattern.quote(String.valueOf(ARRAY_DELIMITER));
JsonArray array = new JsonArray();
for(String element : concat.split(regex)) {
element = element.replace("\\" + ARRAY_DELIMITER, String.valueOf(ARRAY_DELIMITER));
array.add(StringEscapeUtils.unescapeJava(element));
}
return array;
}
public static boolean isArray(String concat) {
return concat != null && concat.startsWith(ARRAY_PREFIX) && concat.endsWith(ARRAY_SUFFIX);
}
}

View File

@ -27,8 +27,13 @@ public class JsonUtil {
public static void writeTree(String locale, JsonObject parent, LocalizedNode node) { public static void writeTree(String locale, JsonObject parent, LocalizedNode node) {
if(node.isLeaf() && !node.getKey().equals(LocalizedNode.ROOT_KEY)) { if(node.isLeaf() && !node.getKey().equals(LocalizedNode.ROOT_KEY)) {
if(node.getValue().get(locale) != null) { if(node.getValue().get(locale) != null) {
String value = StringEscapeUtils.unescapeJava(node.getValue().get(locale));
parent.add(node.getKey(), new JsonPrimitive(value)); if(JsonArrayUtil.isArray(node.getValue().get(locale))) {
parent.add(node.getKey(), JsonArrayUtil.write(node.getValue().get(locale)));
} else {
String value = StringEscapeUtils.unescapeJava(node.getValue().get(locale));
parent.add(node.getKey(), new JsonPrimitive(value));
}
} }
} else { } else {
@ -78,7 +83,11 @@ public class JsonUtil {
} }
Map<String, String> messages = leafNode.getValue(); Map<String, String> messages = leafNode.getValue();
String value = StringUtil.escapeControls(entry.getValue().getAsString(), true);
String value = entry.getValue().isJsonArray()
? JsonArrayUtil.read(entry.getValue().getAsJsonArray())
: StringUtil.escapeControls(entry.getValue().getAsString(), true);
messages.put(locale, value); messages.put(locale, value);
leafNode.setValue(messages); leafNode.setValue(messages);
} }

View File

@ -0,0 +1,8 @@
<idea-plugin>
<extensions defaultExtensionNs="com.intellij">
<annotator language="kotlin" implementationClass="de.marhali.easyi18n.editor.kotlin.KotlinKeyAnnotator" />
<completion.contributor language="kotlin"
implementationClass="de.marhali.easyi18n.editor.kotlin.KotlinKeyCompletionContributor" />
</extensions>
</idea-plugin>

View File

@ -5,15 +5,17 @@
<!-- Product and plugin compatibility requirements --> <!-- Product and plugin compatibility requirements -->
<!-- https://plugins.jetbrains.com/docs/intellij/plugin-compatibility.html --> <!-- https://plugins.jetbrains.com/docs/intellij/plugin-compatibility.html -->
<depends>com.intellij.modules.platform</depends>
<depends>com.intellij.modules.lang</depends> <depends>com.intellij.modules.lang</depends>
<depends optional="true" config-file="de.marhali.easyi18n-kotlin.xml">org.jetbrains.kotlin</depends>
<extensions defaultExtensionNs="com.intellij"> <extensions defaultExtensionNs="com.intellij">
<toolWindow id="Easy I18n" anchor="bottom" factoryClass="de.marhali.easyi18n.TranslatorToolWindowFactory" /> <toolWindow id="Easy I18n" anchor="bottom" factoryClass="de.marhali.easyi18n.TranslatorToolWindowFactory" />
<projectService serviceImplementation="de.marhali.easyi18n.service.SettingsService" /> <projectService serviceImplementation="de.marhali.easyi18n.service.SettingsService" />
<completion.contributor language="any" <completion.contributor language="any"
implementationClass="de.marhali.easyi18n.ui.editor.I18nCompletionContributor" /> implementationClass="de.marhali.easyi18n.editor.generic.GenericKeyCompletionContributor" />
<annotator language="" implementationClass="de.marhali.easyi18n.ui.editor.I18nKeyAnnotator" /> <annotator language="" implementationClass="de.marhali.easyi18n.editor.generic.GenericKeyAnnotator" />
</extensions> </extensions>
</idea-plugin> </idea-plugin>

View File

@ -14,4 +14,5 @@ translation.locales=Locales
settings.path.title=Locales Directory settings.path.title=Locales Directory
settings.path.text=Locales directory settings.path.text=Locales directory
settings.path.file-pattern=Translation file pattern settings.path.file-pattern=Translation file pattern
settings.preview=Preview locale settings.preview=Preview locale
settings.editor.assistance=I18n key completion and annotation inside editor