commit
e4410c264c
@ -3,6 +3,13 @@
|
|||||||
# easy-i18n Changelog
|
# easy-i18n Changelog
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
### Added
|
||||||
|
- Support for YAML locale files. Thanks to @sunarya-thito
|
||||||
|
- Optional path-prefix for translations
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Optimized i18n key completion
|
||||||
|
|
||||||
## [1.4.1]
|
## [1.4.1]
|
||||||
### Added
|
### Added
|
||||||
- Support for IntelliJ 2021.2
|
- Support for IntelliJ 2021.2
|
||||||
|
17
example/yaml/locale-de.yml
Normal file
17
example/yaml/locale-de.yml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
alpha:
|
||||||
|
spacing: ' führendes Leerzeichen'
|
||||||
|
first: Beispiel Übersetzung
|
||||||
|
beta:
|
||||||
|
title: Titel
|
||||||
|
nested:
|
||||||
|
title: Ein verschachtelter Titel
|
||||||
|
gamma:
|
||||||
|
array:
|
||||||
|
escaped:
|
||||||
|
- Erstes;Element
|
||||||
|
- Zweites Element
|
||||||
|
- Drittes;Element
|
||||||
|
simple:
|
||||||
|
- Erstes Element
|
||||||
|
- Zweites Element
|
||||||
|
title: Gamma Titel
|
17
example/yaml/locale-en.yml
Normal file
17
example/yaml/locale-en.yml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
alpha:
|
||||||
|
spacing: ' leading space'
|
||||||
|
first: Example Translation
|
||||||
|
beta:
|
||||||
|
title: Title
|
||||||
|
nested:
|
||||||
|
title: some nested title
|
||||||
|
gamma:
|
||||||
|
array:
|
||||||
|
escaped:
|
||||||
|
- first;element
|
||||||
|
- second element
|
||||||
|
- third;element
|
||||||
|
simple:
|
||||||
|
- first element
|
||||||
|
- second element
|
||||||
|
title: gamma title
|
@ -26,7 +26,8 @@ public class SettingsDialog {
|
|||||||
|
|
||||||
private TextFieldWithBrowseButton pathText;
|
private TextFieldWithBrowseButton pathText;
|
||||||
private JBTextField filePatternText;
|
private JBTextField filePatternText;
|
||||||
private JBTextField previewText;
|
private JBTextField previewLocaleText;
|
||||||
|
private JBTextField pathPrefixText;
|
||||||
private JBCheckBox codeAssistanceCheckbox;
|
private JBCheckBox codeAssistanceCheckbox;
|
||||||
|
|
||||||
public SettingsDialog(Project project) {
|
public SettingsDialog(Project project) {
|
||||||
@ -37,22 +38,25 @@ 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();
|
||||||
|
String pathPrefix = SettingsService.getInstance(project).getState().getPathPrefix();
|
||||||
boolean codeAssistance = SettingsService.getInstance(project).getState().isCodeAssistance();
|
boolean codeAssistance = SettingsService.getInstance(project).getState().isCodeAssistance();
|
||||||
|
|
||||||
if(prepare(localesPath, filePattern, previewLocale, codeAssistance).show() == DialogWrapper.OK_EXIT_CODE) { // Save changes
|
if(prepare(localesPath, filePattern, previewLocale, pathPrefix, 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(previewLocaleText.getText());
|
||||||
SettingsService.getInstance(project).getState().setCodeAssistance(codeAssistanceCheckbox.isSelected());
|
SettingsService.getInstance(project).getState().setCodeAssistance(codeAssistanceCheckbox.isSelected());
|
||||||
|
SettingsService.getInstance(project).getState().setPathPrefix(pathPrefixText.getText());
|
||||||
|
|
||||||
// Reload instance
|
// Reload instance
|
||||||
DataStore.getInstance(project).reloadFromDisk();
|
DataStore.getInstance(project).reloadFromDisk();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private DialogBuilder prepare(String localesPath, String filePattern, String previewLocale, boolean codeAssistance) {
|
private DialogBuilder prepare(String localesPath, String filePattern, String previewLocale, String pathPrefix, boolean codeAssistance) {
|
||||||
JPanel rootPanel = new JPanel(new GridLayout(0, 1, 2, 2));
|
JPanel rootPanel = new JPanel(new GridLayout(0, 1, 2, 2));
|
||||||
|
|
||||||
|
/* path */
|
||||||
JBLabel pathLabel = new JBLabel(ResourceBundle.getBundle("messages").getString("settings.path.text"));
|
JBLabel pathLabel = new JBLabel(ResourceBundle.getBundle("messages").getString("settings.path.text"));
|
||||||
pathText = new TextFieldWithBrowseButton(new JTextField(localesPath));
|
pathText = new TextFieldWithBrowseButton(new JTextField(localesPath));
|
||||||
|
|
||||||
@ -63,20 +67,29 @@ public class SettingsDialog {
|
|||||||
rootPanel.add(pathLabel);
|
rootPanel.add(pathLabel);
|
||||||
rootPanel.add(pathText);
|
rootPanel.add(pathText);
|
||||||
|
|
||||||
|
/* file pattern */
|
||||||
JBLabel filePatternLabel = new JBLabel(ResourceBundle.getBundle("messages").getString("settings.path.file-pattern"));
|
JBLabel filePatternLabel = new JBLabel(ResourceBundle.getBundle("messages").getString("settings.path.file-pattern"));
|
||||||
filePatternText = new JBTextField(filePattern);
|
filePatternText = new JBTextField(filePattern);
|
||||||
|
|
||||||
rootPanel.add(filePatternLabel);
|
rootPanel.add(filePatternLabel);
|
||||||
rootPanel.add(filePatternText);
|
rootPanel.add(filePatternText);
|
||||||
|
|
||||||
|
/* preview locale */
|
||||||
|
JBLabel previewLocaleLabel = new JBLabel(ResourceBundle.getBundle("messages").getString("settings.preview"));
|
||||||
|
previewLocaleText = new JBTextField(previewLocale);
|
||||||
|
previewLocaleLabel.setLabelFor(previewLocaleText);
|
||||||
|
|
||||||
JBLabel previewLabel = new JBLabel(ResourceBundle.getBundle("messages").getString("settings.preview"));
|
rootPanel.add(previewLocaleLabel);
|
||||||
previewText = new JBTextField(previewLocale);
|
rootPanel.add(previewLocaleText);
|
||||||
previewLabel.setLabelFor(previewText);
|
|
||||||
|
|
||||||
rootPanel.add(previewLabel);
|
/* path prefix */
|
||||||
rootPanel.add(previewText);
|
JBLabel pathPrefixLabel = new JBLabel(ResourceBundle.getBundle("messages").getString("settings.path.prefix"));
|
||||||
|
pathPrefixText = new JBTextField(pathPrefix);
|
||||||
|
|
||||||
|
rootPanel.add(pathPrefixLabel);
|
||||||
|
rootPanel.add(pathPrefixText);
|
||||||
|
|
||||||
|
/* code assistance */
|
||||||
codeAssistanceCheckbox = new JBCheckBox(ResourceBundle.getBundle("messages").getString("settings.editor.assistance"));
|
codeAssistanceCheckbox = new JBCheckBox(ResourceBundle.getBundle("messages").getString("settings.editor.assistance"));
|
||||||
codeAssistanceCheckbox.setSelected(codeAssistance);
|
codeAssistanceCheckbox.setSelected(codeAssistance);
|
||||||
|
|
||||||
|
@ -29,7 +29,17 @@ public class KeyAnnotator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String previewLocale = SettingsService.getInstance(project).getState().getPreviewLocale();
|
String previewLocale = SettingsService.getInstance(project).getState().getPreviewLocale();
|
||||||
LocalizedNode node = DataStore.getInstance(project).getTranslations().getNode(key);
|
String pathPrefix = SettingsService.getInstance(project).getState().getPathPrefix();
|
||||||
|
|
||||||
|
String searchKey = key.length() >= pathPrefix.length()
|
||||||
|
? key.substring(pathPrefix.length())
|
||||||
|
: key;
|
||||||
|
|
||||||
|
if(searchKey.startsWith(".")) {
|
||||||
|
searchKey = searchKey.substring(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalizedNode node = DataStore.getInstance(project).getTranslations().getNode(searchKey);
|
||||||
|
|
||||||
if(node == null) { // Unknown translation. Just ignore it
|
if(node == null) { // Unknown translation. Just ignore it
|
||||||
return;
|
return;
|
||||||
|
@ -1,20 +1,16 @@
|
|||||||
package de.marhali.easyi18n.editor;
|
package de.marhali.easyi18n.editor;
|
||||||
|
|
||||||
import com.intellij.codeInsight.completion.CompletionParameters;
|
import com.intellij.codeInsight.completion.*;
|
||||||
import com.intellij.codeInsight.completion.CompletionProvider;
|
import com.intellij.codeInsight.lookup.*;
|
||||||
import com.intellij.codeInsight.completion.CompletionResultSet;
|
import com.intellij.icons.AllIcons;
|
||||||
import com.intellij.codeInsight.lookup.LookupElementBuilder;
|
import com.intellij.openapi.project.*;
|
||||||
import com.intellij.openapi.project.Project;
|
import com.intellij.util.*;
|
||||||
import com.intellij.util.ProcessingContext;
|
import de.marhali.easyi18n.model.*;
|
||||||
|
import de.marhali.easyi18n.service.*;
|
||||||
import de.marhali.easyi18n.model.LocalizedNode;
|
|
||||||
import de.marhali.easyi18n.service.DataStore;
|
|
||||||
import de.marhali.easyi18n.service.SettingsService;
|
|
||||||
import de.marhali.easyi18n.util.TranslationsUtil;
|
import de.marhali.easyi18n.util.TranslationsUtil;
|
||||||
|
import org.jetbrains.annotations.*;
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import java.util.*;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* I18n translation key completion provider.
|
* I18n translation key completion provider.
|
||||||
@ -33,38 +29,58 @@ public class KeyCompletionProvider extends CompletionProvider<CompletionParamete
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DataStore store = DataStore.getInstance(project);
|
||||||
String previewLocale = SettingsService.getInstance(project).getState().getPreviewLocale();
|
String previewLocale = SettingsService.getInstance(project).getState().getPreviewLocale();
|
||||||
|
String pathPrefix = SettingsService.getInstance(project).getState().getPathPrefix();
|
||||||
|
|
||||||
String query = result.getPrefixMatcher().getPrefix();
|
String path = result.getPrefixMatcher().getPrefix();
|
||||||
List<String> sections = TranslationsUtil.getSections(query);
|
|
||||||
String lastSection = null;
|
|
||||||
|
|
||||||
if(!sections.isEmpty() && !query.endsWith(".")) {
|
if(pathPrefix == null) {
|
||||||
lastSection = sections.remove(sections.size() - 1);
|
pathPrefix = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
String path = TranslationsUtil.sectionsToFullPath(sections);
|
if(path.startsWith(pathPrefix)) {
|
||||||
|
path = path.substring(pathPrefix.length());
|
||||||
|
|
||||||
LocalizedNode node = sections.isEmpty() ? DataStore.getInstance(project).getTranslations().getNodes()
|
if(path.startsWith(".")) { // Remove leading dot
|
||||||
: DataStore.getInstance(project).getTranslations().getNode(path);
|
path = path.substring(1);
|
||||||
|
|
||||||
if(node == null) { // Unknown translation
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for(LocalizedNode children : node.getChildren()) {
|
} else {
|
||||||
if(lastSection == null || children.getKey().startsWith(lastSection)) {
|
path = ""; // Show suggestions for root view
|
||||||
// Construct full key path / Fore nested objects add '.' to indicate deeper level
|
}
|
||||||
String fullKey = (path.isEmpty() ? children.getKey() : path + "." + children.getKey()) + (children.isLeaf() ? "" : ".");
|
|
||||||
|
|
||||||
result.addElement(LookupElementBuilder.create(fullKey)
|
if(pathPrefix.length() > 0 && !pathPrefix.endsWith(".")) {
|
||||||
.appendTailText(getTailText(children, previewLocale), true));
|
pathPrefix += ".";
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> fullKeys = store.getTranslations().getFullKeys();
|
||||||
|
|
||||||
|
int sections = path.split("\\.").length;
|
||||||
|
int maxSectionForwardLookup = 5;
|
||||||
|
|
||||||
|
for(String key : fullKeys) {
|
||||||
|
// Path matches
|
||||||
|
if(key.startsWith(path)) {
|
||||||
|
String[] keySections = key.split("\\.");
|
||||||
|
|
||||||
|
if(keySections.length > sections + maxSectionForwardLookup) { // Key is too deep nested
|
||||||
|
String shrinkKey = TranslationsUtil.sectionsToFullPath(Arrays.asList(
|
||||||
|
Arrays.copyOf(keySections, sections + maxSectionForwardLookup)));
|
||||||
|
|
||||||
|
result.addElement(LookupElementBuilder.create(pathPrefix + shrinkKey)
|
||||||
|
.appendTailText(" I18n([])", true));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
LocalizedNode node = store.getTranslations().getNode(key);
|
||||||
|
String translation = node != null ? node.getValue().get(previewLocale) : null;
|
||||||
|
|
||||||
|
result.addElement(LookupElementBuilder.create(pathPrefix + key)
|
||||||
|
.withIcon(AllIcons.Actions.PreserveCaseHover)
|
||||||
|
.appendTailText(" I18n(" + previewLocale + ": " + translation + ")", true)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getTailText(LocalizedNode node, String previewLocale) {
|
|
||||||
return !node.isLeaf() ? " I18n([])"
|
|
||||||
: " I18n(" + previewLocale + ": " + node.getValue().get(previewLocale) + ")";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,8 @@ package de.marhali.easyi18n.editor.generic;
|
|||||||
import com.intellij.codeInsight.completion.CompletionContributor;
|
import com.intellij.codeInsight.completion.CompletionContributor;
|
||||||
import com.intellij.codeInsight.completion.CompletionType;
|
import com.intellij.codeInsight.completion.CompletionType;
|
||||||
import com.intellij.patterns.*;
|
import com.intellij.patterns.*;
|
||||||
import com.intellij.psi.PsiLiteralValue;
|
import com.intellij.psi.*;
|
||||||
|
import com.intellij.psi.xml.*;
|
||||||
import de.marhali.easyi18n.editor.KeyCompletionProvider;
|
import de.marhali.easyi18n.editor.KeyCompletionProvider;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -13,6 +14,10 @@ import de.marhali.easyi18n.editor.KeyCompletionProvider;
|
|||||||
public class GenericKeyCompletionContributor extends CompletionContributor {
|
public class GenericKeyCompletionContributor extends CompletionContributor {
|
||||||
|
|
||||||
public GenericKeyCompletionContributor() {
|
public GenericKeyCompletionContributor() {
|
||||||
|
extend(CompletionType.BASIC, PlatformPatterns.psiElement(PlainTextTokenTypes.PLAIN_TEXT),
|
||||||
|
new KeyCompletionProvider());
|
||||||
|
extend(CompletionType.BASIC, PlatformPatterns.psiElement().inside(XmlElement.class),
|
||||||
|
new KeyCompletionProvider());
|
||||||
extend(CompletionType.BASIC, PlatformPatterns.psiElement().inside(PsiLiteralValue.class),
|
extend(CompletionType.BASIC, PlatformPatterns.psiElement().inside(PsiLiteralValue.class),
|
||||||
new KeyCompletionProvider());
|
new KeyCompletionProvider());
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,125 @@
|
|||||||
|
package de.marhali.easyi18n.io.implementation;
|
||||||
|
|
||||||
|
import com.intellij.openapi.application.*;
|
||||||
|
import com.intellij.openapi.project.*;
|
||||||
|
import com.intellij.openapi.vfs.*;
|
||||||
|
|
||||||
|
import de.marhali.easyi18n.io.*;
|
||||||
|
import de.marhali.easyi18n.model.*;
|
||||||
|
import de.marhali.easyi18n.util.*;
|
||||||
|
import de.marhali.easyi18n.util.array.YamlArrayUtil;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.*;
|
||||||
|
|
||||||
|
import thito.nodeflow.config.*;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.nio.charset.*;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.function.*;
|
||||||
|
|
||||||
|
public class YamlTranslatorIO implements TranslatorIO {
|
||||||
|
@Override
|
||||||
|
public void read(@NotNull Project project, @NotNull String directoryPath, @NotNull Consumer<Translations> callback) {
|
||||||
|
ApplicationManager.getApplication().saveAll(); // Save opened files (required if new locales were added)
|
||||||
|
|
||||||
|
ApplicationManager.getApplication().runReadAction(() -> {
|
||||||
|
VirtualFile directory = LocalFileSystem.getInstance().findFileByIoFile(new File(directoryPath));
|
||||||
|
|
||||||
|
if(directory == null || directory.getChildren() == null) {
|
||||||
|
throw new IllegalArgumentException("Specified folder is invalid (" + directoryPath + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
VirtualFile[] files = directory.getChildren();
|
||||||
|
|
||||||
|
List<String> locales = new ArrayList<>();
|
||||||
|
LocalizedNode nodes = new LocalizedNode(LocalizedNode.ROOT_KEY, new ArrayList<>());
|
||||||
|
|
||||||
|
try {
|
||||||
|
for(VirtualFile file : files) {
|
||||||
|
|
||||||
|
if(!IOUtil.isFileRelevant(project, file)) { // File does not matches pattern
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
locales.add(file.getNameWithoutExtension());
|
||||||
|
|
||||||
|
try (Reader reader = new InputStreamReader(file.getInputStream(), StandardCharsets.UTF_8)) {
|
||||||
|
Section section = Section.parseToMap(reader);
|
||||||
|
load(file.getNameWithoutExtension(), nodes, section);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
callback.accept(new Translations(locales, nodes));
|
||||||
|
|
||||||
|
} catch(IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
callback.accept(null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void load(String locale, LocalizedNode node, Section section) {
|
||||||
|
if (section instanceof MapSection) {
|
||||||
|
for (String key : section.getKeys()) {
|
||||||
|
LocalizedNode child = node.getChildren(key);
|
||||||
|
if (child == null) {
|
||||||
|
node.addChildren(child = new LocalizedNode(key, new ArrayList<>()));
|
||||||
|
}
|
||||||
|
LocalizedNode finalChild = child;
|
||||||
|
MapSection map = section.getMap(key).orElse(null);
|
||||||
|
if (map != null) {
|
||||||
|
load(locale, finalChild, map);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if(section.isList(key) && section.getList(key).isPresent()) {
|
||||||
|
child.getValue().put(locale, YamlArrayUtil.read(section.getList(key).get()));
|
||||||
|
} else {
|
||||||
|
String value = section.getString(key).orElse(null);
|
||||||
|
if (value != null) {
|
||||||
|
child.getValue().put(locale, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void save(LocalizedNode node, String locale, Section section, String path) {
|
||||||
|
if (node.isLeaf() && !node.getKey().equals(LocalizedNode.ROOT_KEY)) {
|
||||||
|
String value = node.getValue().get(locale);
|
||||||
|
if (value != null) {
|
||||||
|
section.set(path, YamlArrayUtil.isArray(value) ? YamlArrayUtil.write(value) : value);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (LocalizedNode child : node.getChildren()) {
|
||||||
|
save(child, locale, section, path == null ? child.getKey() : path + "." + child.getKey());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void save(@NotNull Project project, @NotNull Translations translations, @NotNull String directoryPath, @NotNull Consumer<Boolean> callback) {
|
||||||
|
ApplicationManager.getApplication().runWriteAction(() -> {
|
||||||
|
try {
|
||||||
|
for(String locale : translations.getLocales()) {
|
||||||
|
Section section = new MapSection();
|
||||||
|
|
||||||
|
save(translations.getNodes(), locale, section, null);
|
||||||
|
|
||||||
|
String fullPath = directoryPath + "/" + locale + ".yml";
|
||||||
|
VirtualFile file = LocalFileSystem.getInstance().findFileByIoFile(new File(fullPath));
|
||||||
|
|
||||||
|
file.setBinaryContent(Section.toString(section).getBytes(file.getCharset()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Successfully saved
|
||||||
|
callback.accept(true);
|
||||||
|
|
||||||
|
} catch(IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
callback.accept(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -16,6 +16,7 @@ public class SettingsState {
|
|||||||
private String localesPath;
|
private String localesPath;
|
||||||
private String filePattern;
|
private String filePattern;
|
||||||
private String previewLocale;
|
private String previewLocale;
|
||||||
|
private String pathPrefix;
|
||||||
private Boolean codeAssistance;
|
private Boolean codeAssistance;
|
||||||
|
|
||||||
public SettingsState() {}
|
public SettingsState() {}
|
||||||
@ -51,4 +52,12 @@ public class SettingsState {
|
|||||||
public void setCodeAssistance(boolean codeAssistance) {
|
public void setCodeAssistance(boolean codeAssistance) {
|
||||||
this.codeAssistance = codeAssistance;
|
this.codeAssistance = codeAssistance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setPathPrefix(String pathPrefix) {
|
||||||
|
this.pathPrefix = pathPrefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPathPrefix() {
|
||||||
|
return pathPrefix;
|
||||||
|
}
|
||||||
}
|
}
|
@ -4,7 +4,6 @@ import com.intellij.openapi.components.PersistentStateComponent;
|
|||||||
import com.intellij.openapi.components.State;
|
import com.intellij.openapi.components.State;
|
||||||
import com.intellij.openapi.project.Project;
|
import com.intellij.openapi.project.Project;
|
||||||
|
|
||||||
import com.intellij.util.xmlb.XmlSerializerUtil;
|
|
||||||
import de.marhali.easyi18n.model.SettingsState;
|
import de.marhali.easyi18n.model.SettingsState;
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
@ -3,9 +3,7 @@ package de.marhali.easyi18n.util;
|
|||||||
import com.intellij.openapi.project.Project;
|
import com.intellij.openapi.project.Project;
|
||||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||||
import com.intellij.openapi.vfs.VirtualFile;
|
import com.intellij.openapi.vfs.VirtualFile;
|
||||||
import de.marhali.easyi18n.io.implementation.JsonTranslatorIO;
|
import de.marhali.easyi18n.io.implementation.*;
|
||||||
import de.marhali.easyi18n.io.implementation.ModularizedJsonTranslatorIO;
|
|
||||||
import de.marhali.easyi18n.io.implementation.PropertiesTranslatorIO;
|
|
||||||
import de.marhali.easyi18n.io.TranslatorIO;
|
import de.marhali.easyi18n.io.TranslatorIO;
|
||||||
|
|
||||||
import de.marhali.easyi18n.service.SettingsService;
|
import de.marhali.easyi18n.service.SettingsService;
|
||||||
@ -50,7 +48,8 @@ public class IOUtil {
|
|||||||
|
|
||||||
case "properties":
|
case "properties":
|
||||||
return new PropertiesTranslatorIO();
|
return new PropertiesTranslatorIO();
|
||||||
|
case "yml":
|
||||||
|
return new YamlTranslatorIO();
|
||||||
default:
|
default:
|
||||||
throw new UnsupportedOperationException("Unsupported i18n locale file format: " +
|
throw new UnsupportedOperationException("Unsupported i18n locale file format: " +
|
||||||
any.get().getFileType().getDefaultExtension());
|
any.get().getFileType().getDefaultExtension());
|
||||||
|
@ -1,51 +0,0 @@
|
|||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
@ -6,6 +6,7 @@ import com.google.gson.JsonPrimitive;
|
|||||||
|
|
||||||
import de.marhali.easyi18n.model.LocalizedNode;
|
import de.marhali.easyi18n.model.LocalizedNode;
|
||||||
|
|
||||||
|
import de.marhali.easyi18n.util.array.JsonArrayUtil;
|
||||||
import org.apache.commons.lang.StringEscapeUtils;
|
import org.apache.commons.lang.StringEscapeUtils;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
58
src/main/java/de/marhali/easyi18n/util/array/ArrayUtil.java
Normal file
58
src/main/java/de/marhali/easyi18n/util/array/ArrayUtil.java
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
package de.marhali.easyi18n.util.array;
|
||||||
|
|
||||||
|
import de.marhali.easyi18n.util.StringUtil;
|
||||||
|
import org.apache.commons.lang.StringEscapeUtils;
|
||||||
|
|
||||||
|
import java.text.MessageFormat;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility methods for simple array support.
|
||||||
|
* @author marhali
|
||||||
|
*/
|
||||||
|
public abstract class ArrayUtil {
|
||||||
|
|
||||||
|
static final String PREFIX = "!arr[";
|
||||||
|
static final String SUFFIX = "]";
|
||||||
|
static final char DELIMITER = ';';
|
||||||
|
|
||||||
|
static final String SPLITERATOR_REGEX =
|
||||||
|
MessageFormat.format("(?<!\\\\){0}", Pattern.quote(String.valueOf(DELIMITER)));
|
||||||
|
|
||||||
|
static <T> String read(Iterator<T> elements, Function<T, String> stringFactory) {
|
||||||
|
StringBuilder builder = new StringBuilder(PREFIX);
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
while(elements.hasNext()) {
|
||||||
|
if(i > 0) {
|
||||||
|
builder.append(DELIMITER);
|
||||||
|
}
|
||||||
|
|
||||||
|
String value = stringFactory.apply(elements.next());
|
||||||
|
|
||||||
|
builder.append(StringUtil.escapeControls(
|
||||||
|
value.replace(String.valueOf(DELIMITER), "\\" + DELIMITER), true));
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.append(SUFFIX);
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void write(String concat, Consumer<String> writeElement) {
|
||||||
|
concat = concat.substring(PREFIX.length(), concat.length() - SUFFIX.length());
|
||||||
|
|
||||||
|
for(String element : concat.split(SPLITERATOR_REGEX)) {
|
||||||
|
element = element.replace("\\" + DELIMITER, String.valueOf(DELIMITER));
|
||||||
|
writeElement.accept(StringEscapeUtils.unescapeJava(element));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isArray(String concat) {
|
||||||
|
return concat != null && concat.startsWith(PREFIX) && concat.endsWith(SUFFIX);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
package de.marhali.easyi18n.util.array;
|
||||||
|
|
||||||
|
import com.google.gson.JsonArray;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility methods to read and write json arrays.
|
||||||
|
* @author marhali
|
||||||
|
*/
|
||||||
|
public class JsonArrayUtil extends ArrayUtil {
|
||||||
|
public static String read(JsonArray array) {
|
||||||
|
return read(array.iterator(), JsonElement::getAsString);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static JsonArray write(String concat) {
|
||||||
|
JsonArray array = new JsonArray();
|
||||||
|
write(concat, array::add);
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
package de.marhali.easyi18n.util.array;
|
||||||
|
|
||||||
|
import thito.nodeflow.config.ListSection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility methods to read and write yaml lists.
|
||||||
|
* @author marhali
|
||||||
|
*/
|
||||||
|
public class YamlArrayUtil extends ArrayUtil {
|
||||||
|
|
||||||
|
public static String read(ListSection list) {
|
||||||
|
return read(list.iterator(), Object::toString);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ListSection write(String concat) {
|
||||||
|
ListSection list = new ListSection();
|
||||||
|
write(concat, list::add);
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
}
|
227
src/main/java/thito/nodeflow/config/ListSection.java
Normal file
227
src/main/java/thito/nodeflow/config/ListSection.java
Normal file
@ -0,0 +1,227 @@
|
|||||||
|
package thito.nodeflow.config;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.*;
|
||||||
|
|
||||||
|
public class ListSection extends ArrayList<Object> implements Section {
|
||||||
|
private Section parent;
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
public ListSection() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ListSection(Collection<?> c) {
|
||||||
|
super();
|
||||||
|
addAll(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setParent(Section parent, String name) {
|
||||||
|
this.parent = parent;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
if (name == null && parent != null) {
|
||||||
|
if (parent instanceof ListSection) {
|
||||||
|
return String.valueOf(((ListSection) parent).indexOf(this));
|
||||||
|
}
|
||||||
|
if (parent instanceof MapSection) {
|
||||||
|
return ((MapSection) parent).entrySet().stream().filter(e -> Objects.equals(e.getValue(), this))
|
||||||
|
.findAny().map(Map.Entry::getKey).orElse(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<Object> getObject(int index) {
|
||||||
|
return index >= 0 && index < size() ? Optional.ofNullable(get(index)) : Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Section getParent() {
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> getKeys() {
|
||||||
|
return IntStream.range(0, size()).mapToObj(String::valueOf).collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<?> getInScope(String key) {
|
||||||
|
try {
|
||||||
|
return Optional.ofNullable(get(Integer.parseInt(key)));
|
||||||
|
} catch (Throwable t) {
|
||||||
|
}
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setInScope(String key, Object value) {
|
||||||
|
try {
|
||||||
|
set(Integer.parseInt(key), value);
|
||||||
|
} catch (Throwable t) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object set(int index, Object element) {
|
||||||
|
element = Section.wrap(element);
|
||||||
|
if (element instanceof Section) element = Section.wrapParent(this, null, (Section) element);
|
||||||
|
return super.set(index, element);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean add(Object o) {
|
||||||
|
o = Section.wrap(o);
|
||||||
|
if (o instanceof Section) o = Section.wrapParent(this, null, (Section) o);
|
||||||
|
return super.add(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void add(int index, Object element) {
|
||||||
|
element = Section.wrap(element);
|
||||||
|
if (element instanceof Section) element = Section.wrapParent(this, null, (Section) element);
|
||||||
|
super.add(index, element);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean addAll(Collection<?> c) {
|
||||||
|
c.forEach(o -> add(o));
|
||||||
|
return !c.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean addAll(int index, Collection<?> c) {
|
||||||
|
List<Object> wrapped = new ArrayList<>();
|
||||||
|
c.forEach(obj -> {
|
||||||
|
Object o = Section.wrap(obj);
|
||||||
|
if (o instanceof Section) o = Section.wrapParent(this, null, (Section) o);
|
||||||
|
wrapped.add(o);
|
||||||
|
});
|
||||||
|
return super.addAll(index, wrapped);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return Section.toString(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T extends Enum<T>> Optional<T> getEnum(int index, Class<T> clz) {
|
||||||
|
return getObject(index).map(o -> {
|
||||||
|
try {
|
||||||
|
return Enum.valueOf(clz, String.valueOf(o));
|
||||||
|
} catch (Throwable t) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<String> getString(int index) {
|
||||||
|
return getObject(index).map(String::valueOf);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<Integer> getInteger(int index) {
|
||||||
|
return getObject(index).map(o -> {
|
||||||
|
try {
|
||||||
|
return Integer.valueOf(String.valueOf(o));
|
||||||
|
} catch (Throwable t) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<Double> getDouble(int index) {
|
||||||
|
return getObject(index).map(o -> {
|
||||||
|
try {
|
||||||
|
return Double.valueOf(String.valueOf(o));
|
||||||
|
} catch (Throwable t) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<Long> getLong(int index) {
|
||||||
|
return getObject(index).map(o -> {
|
||||||
|
try {
|
||||||
|
return Long.valueOf(String.valueOf(o));
|
||||||
|
} catch (Throwable t) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<Float> getFloat(int index) {
|
||||||
|
return getObject(index).map(o -> {
|
||||||
|
try {
|
||||||
|
return Float.valueOf(String.valueOf(o));
|
||||||
|
} catch (Throwable t) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<Short> getShort(int index) {
|
||||||
|
return getObject(index).map(o -> {
|
||||||
|
try {
|
||||||
|
return Short.valueOf(String.valueOf(o));
|
||||||
|
} catch (Throwable t) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<Byte> getByte(int index) {
|
||||||
|
return getObject(index).map(o -> {
|
||||||
|
try {
|
||||||
|
return Byte.valueOf(String.valueOf(o));
|
||||||
|
} catch (Throwable t) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<Character> getCharacter(int index) {
|
||||||
|
return getObject(index).map(o -> {
|
||||||
|
String text = String.valueOf(o);
|
||||||
|
return text.isEmpty() ? null : text.charAt(0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<Boolean> getBoolean(int index) {
|
||||||
|
return getObject(index).map(o -> {
|
||||||
|
String text = String.valueOf(o);
|
||||||
|
return text.equals("true") ? Boolean.TRUE : text.equals("false") ? Boolean.FALSE : null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<MapSection> getMap(int index) {
|
||||||
|
return getObject(index).map(o -> {
|
||||||
|
if (o instanceof Map) {
|
||||||
|
if (o instanceof MapSection) return (MapSection) o;
|
||||||
|
MapSection mapSection = new MapSection((Map<?, ?>) o);
|
||||||
|
mapSection.setParent(this, null);
|
||||||
|
return mapSection;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<ListSection> getList(int index) {
|
||||||
|
return getObject(index).map(o -> {
|
||||||
|
if (o instanceof List) {
|
||||||
|
if (o instanceof ListSection) {
|
||||||
|
return (ListSection) o;
|
||||||
|
}
|
||||||
|
ListSection list = new ListSection((List<?>) o);
|
||||||
|
list.setParent(this, null);
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
ListSection list = new ListSection(Collections.singleton(o));
|
||||||
|
list.setParent(this, null);
|
||||||
|
return list;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
73
src/main/java/thito/nodeflow/config/MapSection.java
Normal file
73
src/main/java/thito/nodeflow/config/MapSection.java
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
package thito.nodeflow.config;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class MapSection extends HashMap<String, Object> implements Section {
|
||||||
|
private Section parent;
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
public MapSection() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public MapSection(Map<?, ?> m) {
|
||||||
|
super();
|
||||||
|
m.forEach((key, value) -> put(String.valueOf(key), value));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setParent(Section parent, String name) {
|
||||||
|
this.parent = parent;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
if (name == null && parent != null) {
|
||||||
|
if (parent instanceof ListSection) {
|
||||||
|
return String.valueOf(((ListSection) parent).indexOf(this));
|
||||||
|
}
|
||||||
|
if (parent instanceof MapSection) {
|
||||||
|
return ((MapSection) parent).entrySet().stream().filter(e -> Objects.equals(e.getValue(), this))
|
||||||
|
.findAny().map(Entry::getKey).orElse(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Section getParent() {
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setInScope(String key, Object value) {
|
||||||
|
put(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object put(String key, Object value) {
|
||||||
|
value = Section.wrap(value);
|
||||||
|
if (value instanceof Section) value = Section.wrapParent(this, key, (Section) value);
|
||||||
|
return super.put(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putAll(Map<? extends String, ?> m) {
|
||||||
|
m.forEach(this::put);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> getKeys() {
|
||||||
|
return keySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<?> getInScope(String key) {
|
||||||
|
return Optional.ofNullable(get(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return Section.toString(this);
|
||||||
|
}
|
||||||
|
}
|
221
src/main/java/thito/nodeflow/config/Section.java
Normal file
221
src/main/java/thito/nodeflow/config/Section.java
Normal file
@ -0,0 +1,221 @@
|
|||||||
|
package thito.nodeflow.config;
|
||||||
|
|
||||||
|
import org.yaml.snakeyaml.*;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.regex.*;
|
||||||
|
|
||||||
|
public interface Section {
|
||||||
|
String SEPARATOR = ".";
|
||||||
|
static Object wrap(Object o) {
|
||||||
|
if (o instanceof Section) return o;
|
||||||
|
if (o instanceof List) {
|
||||||
|
return new ListSection((List<?>) o);
|
||||||
|
}
|
||||||
|
if (o instanceof Map) {
|
||||||
|
return new MapSection((Map<?, ?>) o);
|
||||||
|
}
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
static String getName(String path) {
|
||||||
|
String[] split = path.split(Pattern.quote(SEPARATOR));
|
||||||
|
return split[split.length - 1];
|
||||||
|
}
|
||||||
|
static Section wrapParent(Section parent, String name, Section current) {
|
||||||
|
if (current.getParent() != null && current.getParent() != parent) {
|
||||||
|
if (current instanceof MapSection) {
|
||||||
|
MapSection mapSection = new MapSection((MapSection) current);
|
||||||
|
mapSection.setParent(parent, name);
|
||||||
|
return mapSection;
|
||||||
|
}
|
||||||
|
if (current instanceof ListSection) {
|
||||||
|
ListSection objects = new ListSection((ListSection) current);
|
||||||
|
objects.setParent(parent, name);
|
||||||
|
return objects;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (current instanceof MapSection) {
|
||||||
|
((MapSection) current).setParent(parent, name);
|
||||||
|
}
|
||||||
|
if (current instanceof ListSection) {
|
||||||
|
((ListSection) current).setParent(parent, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
static String toString(Section section) {
|
||||||
|
DumperOptions options = new DumperOptions();
|
||||||
|
options.setIndent(4);
|
||||||
|
options.setAllowUnicode(true);
|
||||||
|
options.setPrettyFlow(true);
|
||||||
|
options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
|
||||||
|
Yaml yaml = new Yaml(options);
|
||||||
|
return yaml.dumpAsMap(section);
|
||||||
|
}
|
||||||
|
static MapSection parseToMap(Reader reader) {
|
||||||
|
Yaml yaml = new Yaml();
|
||||||
|
return new MapSection(yaml.loadAs(reader, Map.class));
|
||||||
|
}
|
||||||
|
Set<String> getKeys();
|
||||||
|
default Set<String> getPaths() {
|
||||||
|
Set<String> paths = new HashSet<>();
|
||||||
|
for (String k : getKeys()) {
|
||||||
|
Object lookup = getInScope(k).orElse(null);
|
||||||
|
if (lookup instanceof Section) {
|
||||||
|
for (String p : ((Section) lookup).getPaths()) {
|
||||||
|
paths.add(k + "." + p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return paths;
|
||||||
|
}
|
||||||
|
String getName();
|
||||||
|
default String getPath() {
|
||||||
|
StringBuilder path = new StringBuilder(getName());
|
||||||
|
Section parent;
|
||||||
|
while ((parent = getParent()) != null) {
|
||||||
|
path.insert(0, parent.getName() + SEPARATOR);
|
||||||
|
}
|
||||||
|
return path.toString();
|
||||||
|
}
|
||||||
|
Section getParent();
|
||||||
|
Optional<?> getInScope(String key);
|
||||||
|
void setInScope(String key, Object value);
|
||||||
|
default void set(String path, Object value) {
|
||||||
|
String[] paths = path.split(Pattern.quote(SEPARATOR));
|
||||||
|
Object lookup = this;
|
||||||
|
for (int i = 0; i < paths.length - 1; i++) {
|
||||||
|
Section oldLookup = (Section) lookup;
|
||||||
|
lookup = oldLookup.getInScope(paths[i]).orElse(null);
|
||||||
|
if (!(lookup instanceof Section)) {
|
||||||
|
oldLookup.setInScope(paths[i], lookup = new MapSection());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (paths.length > 0) {
|
||||||
|
((Section) lookup).setInScope(paths[paths.length - 1], value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default Optional<?> getObject(String path) {
|
||||||
|
String[] paths = path.split(Pattern.quote(SEPARATOR));
|
||||||
|
Object lookup = this;
|
||||||
|
for (String s : paths) {
|
||||||
|
if (lookup instanceof Section) {
|
||||||
|
lookup = ((Section) lookup).getInScope(s).orElse(null);
|
||||||
|
} else {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Optional.ofNullable(lookup);
|
||||||
|
}
|
||||||
|
default <T extends Enum<T>> Optional<T> getEnum(String path, Class<T> clz) {
|
||||||
|
return getObject(path).map(o -> {
|
||||||
|
try {
|
||||||
|
return Enum.valueOf(clz, String.valueOf(o));
|
||||||
|
} catch (Throwable t) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
default Optional<String> getString(String path) {
|
||||||
|
return getObject(path).map(String::valueOf);
|
||||||
|
}
|
||||||
|
default Optional<Integer> getInteger(String path) {
|
||||||
|
return getObject(path).map(o -> {
|
||||||
|
try {
|
||||||
|
return Integer.valueOf(String.valueOf(o));
|
||||||
|
} catch (Throwable t) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
default Optional<Double> getDouble(String path) {
|
||||||
|
return getObject(path).map(o -> {
|
||||||
|
try {
|
||||||
|
return Double.valueOf(String.valueOf(o));
|
||||||
|
} catch (Throwable t) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
default Optional<Long> getLong(String path) {
|
||||||
|
return getObject(path).map(o -> {
|
||||||
|
try {
|
||||||
|
return Long.valueOf(String.valueOf(o));
|
||||||
|
} catch (Throwable t) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
default Optional<Float> getFloat(String path) {
|
||||||
|
return getObject(path).map(o -> {
|
||||||
|
try {
|
||||||
|
return Float.valueOf(String.valueOf(o));
|
||||||
|
} catch (Throwable t) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
default Optional<Short> getShort(String path) {
|
||||||
|
return getObject(path).map(o -> {
|
||||||
|
try {
|
||||||
|
return Short.valueOf(String.valueOf(o));
|
||||||
|
} catch (Throwable t) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
default Optional<Byte> getByte(String path) {
|
||||||
|
return getObject(path).map(o -> {
|
||||||
|
try {
|
||||||
|
return Byte.valueOf(String.valueOf(o));
|
||||||
|
} catch (Throwable t) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
default Optional<Character> getCharacter(String path) {
|
||||||
|
return getObject(path).map(o -> {
|
||||||
|
String text = String.valueOf(o);
|
||||||
|
return text.isEmpty() ? null : text.charAt(0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
default Optional<Boolean> getBoolean(String path) {
|
||||||
|
return getObject(path).map(o -> {
|
||||||
|
String text = String.valueOf(o);
|
||||||
|
return text.equals("true") ? Boolean.TRUE : text.equals("false") ? Boolean.FALSE : null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
default Optional<MapSection> getMap(String path) {
|
||||||
|
return getObject(path).map(o -> {
|
||||||
|
if (o instanceof Map) {
|
||||||
|
if (o instanceof MapSection) return (MapSection) o;
|
||||||
|
MapSection mapSection = new MapSection((Map<?, ?>) o);
|
||||||
|
mapSection.setParent(this, Section.getName(path));
|
||||||
|
return mapSection;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
default boolean isList(String path) {
|
||||||
|
Optional<?> o = getObject(path);
|
||||||
|
return o.isPresent() && o.get() instanceof List;
|
||||||
|
}
|
||||||
|
|
||||||
|
default Optional<ListSection> getList(String path) {
|
||||||
|
return getObject(path).map(o -> {
|
||||||
|
if (o instanceof List) {
|
||||||
|
if (o instanceof ListSection) {
|
||||||
|
return (ListSection) o;
|
||||||
|
}
|
||||||
|
ListSection list = new ListSection((List<?>) o);
|
||||||
|
list.setParent(this, Section.getName(path));
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
ListSection list = new ListSection(Collections.singleton(o));
|
||||||
|
list.setParent(this, Section.getName(path));
|
||||||
|
return list;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -14,5 +14,6 @@ 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.path.prefix=Path prefix
|
||||||
settings.preview=Preview locale
|
settings.preview=Preview locale
|
||||||
settings.editor.assistance=I18n key completion and annotation inside editor
|
settings.editor.assistance=I18n key completion and annotation inside editor
|
Loading…
x
Reference in New Issue
Block a user