diff --git a/src/main/java/de/vette/idea/neos/LocaleDialogWrapper.java b/src/main/java/de/vette/idea/neos/LocaleDialogWrapper.java new file mode 100644 index 0000000..86178a0 --- /dev/null +++ b/src/main/java/de/vette/idea/neos/LocaleDialogWrapper.java @@ -0,0 +1,59 @@ +package de.vette.idea.neos; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.DialogPanel; +import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.openapi.ui.ValidationInfo; +import com.intellij.ui.components.JBLabel; +import com.intellij.ui.components.JBPanel; +import com.intellij.ui.components.JBTextField; +import com.intellij.util.ui.FormBuilder; +import com.intellij.util.ui.JBUI; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.beans.EventHandler; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +public class LocaleDialogWrapper extends DialogWrapper { + JBTextField textField = new JBTextField(); + + Pattern pattern = Pattern.compile("^[A-Za-z]{2,4}([_-][A-Za-z]{4})?([_-]([A-Za-z]{2}|[0-9]{3}))?$"); + + public LocaleDialogWrapper(Project project, String title) { + super(project); + setTitle(title); + init(); + } + + @Override + protected @Nullable JComponent createCenterPanel() { + FormBuilder formBuilder = FormBuilder.createFormBuilder(); + formBuilder.addLabeledComponent("Locale", this.textField); + return formBuilder.getPanel(); + } + + public String getText() { + return this.textField.getText().trim(); + } + + @Override + protected @Nullable ValidationInfo doValidate() { + if (!pattern.matcher(this.getText()).matches()) { + return new ValidationInfo("Test", this.textField); + } + + return null; + } + + @Override + public @Nullable JComponent getPreferredFocusedComponent() { + return this.textField; + } +} diff --git a/src/main/java/de/vette/idea/neos/Settings.java b/src/main/java/de/vette/idea/neos/Settings.java index 50b954f..e0e3e57 100644 --- a/src/main/java/de/vette/idea/neos/Settings.java +++ b/src/main/java/de/vette/idea/neos/Settings.java @@ -24,6 +24,10 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.LinkedList; +import java.util.List; +import java.util.Vector; + @State(name = "NeosPluginSettings") public class Settings implements PersistentStateComponent { @@ -31,6 +35,8 @@ public class Settings implements PersistentStateComponent { public boolean dismissEnableNotification = false; public boolean excludePackageSymlinks = false; + public List locales = new LinkedList<>(); + public static Settings getInstance(@NotNull Project project) { return project.getService(Settings.class); } diff --git a/src/main/java/de/vette/idea/neos/SettingsForm.java b/src/main/java/de/vette/idea/neos/SettingsForm.java index 2012bf8..3773acd 100644 --- a/src/main/java/de/vette/idea/neos/SettingsForm.java +++ b/src/main/java/de/vette/idea/neos/SettingsForm.java @@ -20,8 +20,16 @@ import com.intellij.ide.actions.ShowSettingsUtilImpl; import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.ui.AnActionButton; +import com.intellij.ui.AnActionButtonRunnable; +import com.intellij.ui.CollectionListModel; +import com.intellij.ui.ToolbarDecorator; +import com.intellij.ui.components.JBLabel; +import com.intellij.ui.components.JBList; import com.intellij.uiDesigner.core.GridConstraints; import com.intellij.uiDesigner.core.GridLayoutManager; +import com.intellij.uiDesigner.core.Spacer; import com.jetbrains.php.frameworks.PhpFrameworkConfigurable; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NonNls; @@ -29,10 +37,14 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; +import java.awt.*; +import java.util.ArrayList; +import java.util.function.Consumer; public class SettingsForm implements PhpFrameworkConfigurable { private JCheckBox pluginEnabled; private JCheckBox excludePackageSymlinks; + private CollectionListModel locales; private final Project project; public SettingsForm(@NotNull final Project project) { @@ -66,8 +78,17 @@ public String getHelpTopic() { public JComponent createComponent() { pluginEnabled = new JCheckBox("Enable plugin for this project"); excludePackageSymlinks = new JCheckBox("Exclude symlinked packages"); + locales = new CollectionListModel<>(); - GridLayoutManager layout = new GridLayoutManager(2,1); + JBList localeList = new JBList(); + localeList.setModel(this.locales); + + ToolbarDecorator editableList = ToolbarDecorator.createDecorator(localeList); + editableList.disableUpDownActions(); + editableList.setPreferredSize(new Dimension(150, 100)); + editableList.setAddAction(new AddAction(this.locales)); + + GridLayoutManager layout = new GridLayoutManager(5,1); GridConstraints c = new GridConstraints(); c.setAnchor(GridConstraints.ANCHOR_NORTHWEST); c.setRow(0); @@ -77,12 +98,37 @@ public JComponent createComponent() { c.setRow(1); panel1.add(excludePackageSymlinks, c); + + c.setRow(2); + panel1.add(new Spacer(), c); + + c.setRow(3); + panel1.add(new JBLabel("Locales"), c); + + c.setRow(4); + panel1.add(editableList.createPanel(), c); + return panel1; } @Override public boolean isModified() { - return !pluginEnabled.isSelected() == getSettings().pluginEnabled || !excludePackageSymlinks.isSelected() == getSettings().excludePackageSymlinks; + int i = 0; + + if (getSettings().locales.size() != locales.getSize()) { + return true; + } + + for (String item : locales.getItems()) { + if (!item.equals(getSettings().locales.get(i))) { + return true; + } + + i++; + } + + return !pluginEnabled.isSelected() == getSettings().pluginEnabled + || !excludePackageSymlinks.isSelected() == getSettings().excludePackageSymlinks; } @Override @@ -93,6 +139,7 @@ public void apply() { getSettings().pluginEnabled = pluginEnabled.isSelected(); getSettings().excludePackageSymlinks = excludePackageSymlinks.isSelected(); + getSettings().locales = new ArrayList<>(locales.getItems()); } @Override @@ -103,6 +150,9 @@ public void reset() { private void updateUIFromSettings() { pluginEnabled.setSelected(getSettings().pluginEnabled); excludePackageSymlinks.setSelected(getSettings().excludePackageSymlinks); + getSettings().locales.forEach(s -> { + locales.add(s); + }); } private Settings getSettings() { @@ -112,4 +162,27 @@ private Settings getSettings() { public static void show(@NotNull Project project) { ShowSettingsUtilImpl.showSettingsDialog(project, "Neos.SettingsForm", null); } + + + class AddAction implements AnActionButtonRunnable { + + CollectionListModel list; + + public AddAction(CollectionListModel list) { + this.list = list; + } + + @Override + public void run(AnActionButton anActionButton) { + LocaleDialogWrapper dialog = new LocaleDialogWrapper(project, "Add Locale"); + if (dialog.showAndGet()) { + String text = dialog.getText(); + if (text.isEmpty()) { + return; + } + + this.list.add(text); + } + } + } } diff --git a/src/main/java/de/vette/idea/neos/actions/TranslateNodeTypeAction.java b/src/main/java/de/vette/idea/neos/actions/TranslateNodeTypeAction.java new file mode 100644 index 0000000..f2cf954 --- /dev/null +++ b/src/main/java/de/vette/idea/neos/actions/TranslateNodeTypeAction.java @@ -0,0 +1,392 @@ +package de.vette.idea.neos.actions; + +import com.intellij.ide.fileTemplates.FileTemplate; +import com.intellij.ide.fileTemplates.FileTemplateManager; +import com.intellij.json.psi.JsonFile; +import com.intellij.notification.*; +import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.command.WriteCommandAction; +import com.intellij.openapi.fileTypes.FileTypeManager; +import com.intellij.openapi.fileTypes.FileTypeRegistry; +import com.intellij.openapi.options.ShowSettingsUtil; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.xml.XmlAttribute; +import com.intellij.psi.xml.XmlFile; +import com.intellij.psi.xml.XmlTag; +import com.intellij.util.IncorrectOperationException; +import com.intellij.util.xml.DomFileElement; +import com.intellij.util.xml.DomManager; +import de.vette.idea.neos.Settings; +import de.vette.idea.neos.lang.xliff.XliffDomElement; +import de.vette.idea.neos.lang.xliff.XliffFileType; +import de.vette.idea.neos.util.ComposerUtil; +import de.vette.idea.neos.util.NeosUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.yaml.YAMLElementGenerator; +import org.jetbrains.yaml.psi.*; + +import java.io.IOException; +import java.util.*; + +public class TranslateNodeTypeAction extends AnAction { + + @Override + public void update(@NotNull AnActionEvent e) { + @Nullable Project project = getEventProject(e); + @Nullable VirtualFile virtualFile = e.getDataContext().getData(PlatformDataKeys.VIRTUAL_FILE); + + if (project == null || virtualFile == null) { + e.getPresentation().setEnabledAndVisible(false); + return; + } + + if (!Settings.getInstance(project).pluginEnabled || !ActionPlaces.isPopupPlace(e.getPlace())) { + e.getPresentation().setEnabledAndVisible(false); + return; + } + + if (!NeosUtil.isNodeTypeDefinition(virtualFile)) { + e.getPresentation().setEnabledAndVisible(false); + } + } + + @Override + public void actionPerformed(@NotNull AnActionEvent e) { + @Nullable VirtualFile virtualFile = e.getDataContext().getData(PlatformDataKeys.VIRTUAL_FILE); + @Nullable Project project = getEventProject(e); + + if (project == null || virtualFile == null) { + return; + } + + List pairs = getTranslateablePaths(virtualFile, project); + String nodeType = extractNodeType(pairs); + + PsiDirectory psiDirectory = PsiManager.getInstance(project).findDirectory(virtualFile.getParent()); + JsonFile composerManifest = ComposerUtil.getComposerManifest(psiDirectory); + PsiDirectory packageDirectory; + if (composerManifest == null) { + return; + } + + String packageName = ComposerUtil.getPackageKey(composerManifest); + packageDirectory = composerManifest.getContainingDirectory(); + Collection locales = Settings.getInstance(project).locales; + + if (locales.isEmpty()) { + showNotification(project); + return; + } + + final Optional firstLocaleOpt = locales.stream().findFirst(); + if (firstLocaleOpt.isEmpty()) { + return; + } + + final String sourceLocale = firstLocaleOpt.get(); + + Properties properties = new Properties(); + properties.setProperty("NEOS_PACKAGE_NAME", packageName); + properties.setProperty("SOURCE_LANGUAGE", sourceLocale); + + HashMap yamlPairsByTransId = extractNodeTypeTranslationIds(pairs); + + WriteCommandAction.runWriteCommandAction(project, () -> { + for (String locale : locales) { + PsiDirectory translationDir = createTranslationDirectories(packageDirectory, locale, nodeType); + processTranslationFile(project, translationDir, locale, sourceLocale, yamlPairsByTransId, properties, nodeType); + } + + // replace text values in node type defintion by "i18n" + yamlPairsByTransId.forEach((transId, yamlKeyValue) -> { + if (!yamlKeyValue.getValueText().equals("i18n")) { + YAMLKeyValue newKeyValue = YAMLElementGenerator.getInstance(project).createYamlKeyValue(yamlKeyValue.getKeyText(), "i18n"); + yamlKeyValue.replace(newKeyValue); + } + }); + }); + } + + private static void showNotification(@NotNull Project project) { + NotificationGroupManager.getInstance() + .getNotificationGroup("Neos") + .createNotification("You don't have any locales configured", NotificationType.ERROR) + .addAction(new NotificationAction("Configure locales") { + @Override + public void actionPerformed(@NotNull AnActionEvent e, @NotNull Notification notification) { + ShowSettingsUtil.getInstance().showSettingsDialog(project, "Neos"); + + } + }).notify(project); + } + + private void processTranslationFile( + Project project, + PsiDirectory dir, + String locale, + String sourceLocale, + Map yamlPairsByTransId, + Properties properties, + String nodeType + ) { + String fileName = getFileName(nodeType); + String[] nodeTypeParts = nodeType.split("\\."); + for (String nodeTypePart : nodeTypeParts) { + if (nodeTypePart.equals(fileName)) { + continue; + } + + dir = createSubdirectory(dir, nodeTypePart); + } + + if (!locale.equals(sourceLocale)) { + properties.setProperty("TARGET_LANGUAGE", locale); + } + + try { + fileName = fileName.concat(XliffFileType.DOT_DEFAULT_EXTENSION); + createOrUpdateFileInDirectory(project, dir, fileName, properties); + + Set existingIds = getExistingIdsForFile(dir, fileName); + updateTranslationFileContent(project, dir, fileName, existingIds, yamlPairsByTransId, locale, sourceLocale); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + } + + private String getFileName(String nodeType) { + String[] nodeTypeParts = nodeType.split("\\."); + return nodeTypeParts[nodeTypeParts.length - 1]; + } + + private String extractNodeType(List pairs) { + String nodeType = getTranslationKeyParts(pairs.get(0)).get(0); + String[] nodeTypeParts = nodeType.split(":"); + return (nodeTypeParts.length == 2) ? nodeTypeParts[1] : nodeType; + } + + private PsiDirectory createTranslationDirectories(PsiDirectory baseDir, String locale, String nodeType) throws IncorrectOperationException { + PsiDirectory dir = createSubdirectory(baseDir, "Resources"); + dir = createSubdirectory(dir, "Private"); + PsiDirectory translationsDir = createSubdirectory(dir, "Translations"); + dir = createSubdirectory(translationsDir, locale); + dir = createSubdirectory(dir, "NodeTypes"); + + String[] nodeTypeParts = nodeType.split("\\."); + for (int i = 0; i < nodeTypeParts.length - 1; i++) { + dir = createSubdirectory(dir, nodeTypeParts[i]); + } + return dir; + } + + private Set getExistingIdsForFile(PsiDirectory dir, String fileName) { + XmlFile xmlFile = (XmlFile) dir.findFile(fileName); + if (xmlFile == null) { + return Collections.emptySet(); + } + + XmlTag rootTag = xmlFile.getRootTag(); + if (rootTag == null) { + return Collections.emptySet(); + } + + XmlTag fileTag = rootTag.findFirstSubTag("file"); + if (fileTag == null) { + return Collections.emptySet(); + } + + XmlTag bodyTag = fileTag.findFirstSubTag("body"); + if (bodyTag == null) { + return Collections.emptySet(); + } + + return getExistingIds(bodyTag); + } + + private LinkedHashMap extractNodeTypeTranslationIds(List pairs) { + LinkedHashMap nodeTypeIds = new LinkedHashMap<>(); + for (YAMLKeyValue pair : pairs) { + List path = getTranslationKeyParts(pair); + path = path.subList(1, path.size()); // removes the node type name + String id = String.join(".", path); + nodeTypeIds.put(id, pair); + } + return nodeTypeIds; + } + + private static Set getExistingIds(XmlTag body) { + Set ids = new HashSet<>(); + for (XmlTag subTag : body.findSubTags("trans-unit")) { + XmlAttribute attribute = subTag.getAttribute("id"); + if (attribute == null) { + continue; + } + + ids.add(attribute.getValue()); + } + + return ids; + } + + private static PsiDirectory createSubdirectory(PsiDirectory directory, String name) throws IncorrectOperationException { + PsiDirectory subDirectory = directory.findSubdirectory(name); + + if (subDirectory != null) { + return subDirectory; + } + + subDirectory = directory.createSubdirectory(name); + return subDirectory; + } + + private static List getTranslateablePaths(VirtualFile virtualFile, Project project) { + @NotNull PsiManager psiManager = PsiManager.getInstance(project); + PsiFile psiFile = psiManager.findFile(virtualFile); + + @NotNull Collection yamlKeyValuePairs = PsiTreeUtil.findChildrenOfType(psiFile, YAMLKeyValue.class); + + List pathsToTranslate = new Vector<>(); + for (YAMLKeyValue pair : yamlKeyValuePairs) { + String value = pair.getValueText(); + String key = pair.getKeyText(); + + if (value.equals("i18n")) { + pathsToTranslate.add(pair); + continue; + } + + // *.ui.label + if (key.equals("label")) { + YAMLKeyValue keyValue = (YAMLKeyValue) pair.getParent().getParent(); + if (keyValue.getKeyText().equals("ui")) { + pathsToTranslate.add(pair); + } + continue; + } + + // *.help.message + if (key.equals("message")) { + YAMLKeyValue keyValue = (YAMLKeyValue) pair.getParent().getParent(); + if (keyValue.getKeyText().equals("help")) { + pathsToTranslate.add(pair); + } + continue; + } + + // *.editorOptions.placeholder + if (key.equals("placeholder")) { + YAMLKeyValue keyValue = (YAMLKeyValue) pair.getParent().getParent(); + if (keyValue.getKeyText().equals("editorOptions")) { + pathsToTranslate.add(pair); + } + } + } + + return pathsToTranslate; + } + + private static List getTranslationKeyParts(YAMLKeyValue pair) { + PsiElement parent = pair.getParent(); + List pathParts = new Vector<>(); + pathParts.add(pair.getKeyText()); + + while (!(parent == null || parent instanceof YAMLDocument || parent instanceof YAMLFile)) { + if (parent instanceof YAMLKeyValue + && !(parent.getParent() instanceof YAMLDocument || parent.getParent() instanceof YAMLFile)) { + String currentKey = ((YAMLKeyValue) parent).getKeyText(); + pathParts.add(currentKey); + } + + parent = parent.getParent(); + } + + Collections.reverse(pathParts); + return pathParts; + } + + private void createOrUpdateFileInDirectory(Project project, PsiDirectory dir, String fileName, Properties properties) throws IOException { + FileTemplate template = FileTemplateManager.getInstance(project).getInternalTemplate("XLIFF File"); + String content = template.getText(properties); + if (FileTypeManager.getInstance().isFileIgnored(fileName)) { + throw new IncorrectOperationException("This filename is ignored (Settings | Editor | FileDomElement Types | Ignore files and folders)"); + } + PsiFile psiFile = dir.findFile(fileName); + if (psiFile == null) { + psiFile = PsiFileFactory.getInstance(project).createFileFromText(fileName, FileTypeRegistry.getInstance().getFileTypeByFileName(fileName), content); + dir.add(psiFile); + } + } + + private void updateTranslationFileContent(Project project, PsiDirectory dir, String fileName, Set existingIds, Map yamlPairsByTransId, String locale, String sourceLocale) { + XmlFile xmlFile = (XmlFile) dir.findFile(fileName); + if (xmlFile == null) { + return; + } + + XmlTag rootTag = xmlFile.getRootTag(); + if (rootTag == null) { + return; + } + + XmlTag fileTag = rootTag.findFirstSubTag("file"); + if (fileTag == null) { + return; + } + + XmlTag bodyTag = fileTag.findFirstSubTag("body"); + + Set removedIds = new HashSet<>(existingIds); + removedIds.removeAll(yamlPairsByTransId.keySet()); + + DomManager manager = DomManager.getDomManager(project); + DomFileElement fileElement = manager.getFileElement(xmlFile, XliffDomElement.class); + + if (fileElement == null) { + return; + } + + XliffDomElement root = fileElement.getRootElement(); + removeObsoleteTranslations(root, removedIds); + addNewTranslations(bodyTag, yamlPairsByTransId, existingIds, sourceLocale, locale); + } + + private void removeObsoleteTranslations(XliffDomElement root, Set removedIds) { + root.getFiles().forEach(file -> file.getBody().getTransUnits().forEach(transUnit -> { + if (removedIds.contains(transUnit.getId().getValue())) { + if (transUnit.getXmlElement() != null) { + transUnit.getXmlElement().delete(); + } + } + })); + } + + private void addNewTranslations(XmlTag bodyTag, Map yamlPairsByTransId, Set existingIds, String sourceLocale, String locale) { + yamlPairsByTransId.forEach((id, yamlKeyValue) -> { + if (existingIds.contains(id)) { + return; + } + + XmlTag transUnit = bodyTag.createChildTag("trans-unit", null, null, false); + transUnit.setAttribute("id", id); + + String sourceValue = ""; + if (!yamlKeyValue.getValueText().equals("i18n")) { + sourceValue = yamlKeyValue.getValueText(); + } + + XmlTag sourceTag = transUnit.createChildTag("source", null, sourceValue, false); + transUnit.addSubTag(sourceTag, false); + + if (!locale.equals(sourceLocale)) { + XmlTag target = transUnit.createChildTag("target", null, "", false); + transUnit.addSubTag(target, false); + } + + bodyTag.addSubTag(transUnit, false); + }); + } +} diff --git a/src/main/java/de/vette/idea/neos/lang/xliff/BodyDomElement.java b/src/main/java/de/vette/idea/neos/lang/xliff/BodyDomElement.java new file mode 100644 index 0000000..01a6b3f --- /dev/null +++ b/src/main/java/de/vette/idea/neos/lang/xliff/BodyDomElement.java @@ -0,0 +1,9 @@ +package de.vette.idea.neos.lang.xliff; + +import com.intellij.util.xml.DomElement; + +import java.util.List; + +public interface BodyDomElement extends DomElement { + List getTransUnits(); +} diff --git a/src/main/java/de/vette/idea/neos/lang/xliff/FileDomElement.java b/src/main/java/de/vette/idea/neos/lang/xliff/FileDomElement.java new file mode 100644 index 0000000..d4364da --- /dev/null +++ b/src/main/java/de/vette/idea/neos/lang/xliff/FileDomElement.java @@ -0,0 +1,7 @@ +package de.vette.idea.neos.lang.xliff; + +import com.intellij.util.xml.DomElement; + +public interface FileDomElement extends DomElement { + BodyDomElement getBody(); +} \ No newline at end of file diff --git a/src/main/java/de/vette/idea/neos/lang/xliff/SourceDomElement.java b/src/main/java/de/vette/idea/neos/lang/xliff/SourceDomElement.java new file mode 100644 index 0000000..823ff3a --- /dev/null +++ b/src/main/java/de/vette/idea/neos/lang/xliff/SourceDomElement.java @@ -0,0 +1,7 @@ +package de.vette.idea.neos.lang.xliff; + +import com.intellij.util.xml.DomElement; + +public interface SourceDomElement extends DomElement { + String getValue(); +} diff --git a/src/main/java/de/vette/idea/neos/lang/xliff/TargetDomElement.java b/src/main/java/de/vette/idea/neos/lang/xliff/TargetDomElement.java new file mode 100644 index 0000000..74f030e --- /dev/null +++ b/src/main/java/de/vette/idea/neos/lang/xliff/TargetDomElement.java @@ -0,0 +1,7 @@ +package de.vette.idea.neos.lang.xliff; + +import com.intellij.util.xml.DomElement; + +public interface TargetDomElement extends DomElement { + String getValue(); +} diff --git a/src/main/java/de/vette/idea/neos/lang/xliff/TransUnitDomElement.java b/src/main/java/de/vette/idea/neos/lang/xliff/TransUnitDomElement.java new file mode 100644 index 0000000..d9fb9bd --- /dev/null +++ b/src/main/java/de/vette/idea/neos/lang/xliff/TransUnitDomElement.java @@ -0,0 +1,12 @@ +package de.vette.idea.neos.lang.xliff; + +import com.intellij.util.xml.DomElement; +import com.intellij.util.xml.GenericAttributeValue; + +public interface TransUnitDomElement extends DomElement { + SourceDomElement getSource(); + + TargetDomElement getTarget(); + + GenericAttributeValue getId(); +} diff --git a/src/main/java/de/vette/idea/neos/lang/xliff/XliffDomElement.java b/src/main/java/de/vette/idea/neos/lang/xliff/XliffDomElement.java new file mode 100644 index 0000000..aa8e5be --- /dev/null +++ b/src/main/java/de/vette/idea/neos/lang/xliff/XliffDomElement.java @@ -0,0 +1,11 @@ +package de.vette.idea.neos.lang.xliff; + +import com.intellij.util.xml.DomElement; + +import java.util.List; + +public interface XliffDomElement extends DomElement { + List getFiles(); +} + + diff --git a/src/main/java/de/vette/idea/neos/lang/xliff/XliffDomFileDescription.java b/src/main/java/de/vette/idea/neos/lang/xliff/XliffDomFileDescription.java new file mode 100644 index 0000000..acf114a --- /dev/null +++ b/src/main/java/de/vette/idea/neos/lang/xliff/XliffDomFileDescription.java @@ -0,0 +1,18 @@ +package de.vette.idea.neos.lang.xliff; + +import com.intellij.openapi.module.Module; +import com.intellij.psi.xml.XmlFile; +import com.intellij.util.xml.DomFileDescription; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class XliffDomFileDescription extends DomFileDescription { + public XliffDomFileDescription() { + super(XliffDomElement.class, "xliff"); + } + + @Override + public boolean isMyFile(@NotNull XmlFile file, @Nullable Module module) { + return file.getFileType() == XliffFileType.INSTANCE; + } +} diff --git a/src/main/java/de/vette/idea/neos/lang/xliff/XliffFileType.java b/src/main/java/de/vette/idea/neos/lang/xliff/XliffFileType.java index 609186f..a1c485c 100644 --- a/src/main/java/de/vette/idea/neos/lang/xliff/XliffFileType.java +++ b/src/main/java/de/vette/idea/neos/lang/xliff/XliffFileType.java @@ -1,19 +1,16 @@ package de.vette.idea.neos.lang.xliff; +import com.intellij.ide.highlighter.DomSupportEnabled; import com.intellij.ide.highlighter.XmlLikeFileType; import com.intellij.lang.Language; -import com.intellij.lang.html.HTMLLanguage; -import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.util.NlsContexts; import com.intellij.openapi.util.NlsSafe; -import de.vette.idea.neos.NeosIcons; -import de.vette.idea.neos.lang.eel.EelFileType; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import javax.swing.*; -public class XliffFileType extends XmlLikeFileType { +public class XliffFileType extends XmlLikeFileType implements DomSupportEnabled { @NonNls public static final String DOT_DEFAULT_EXTENSION = ".xlf"; public static final XliffFileType INSTANCE = new XliffFileType(); @@ -22,10 +19,6 @@ private XliffFileType() { super(XliffLanguage.INSTANCE); } - protected XliffFileType(Language language) { - super(language); - } - @Override public @NonNls @NotNull String getName() { return "Neos XLIFF"; @@ -37,7 +30,7 @@ protected XliffFileType(Language language) { } @Override - public @NlsSafe @NotNull String getDefaultExtension() { + public @NotNull String getDefaultExtension() { return "xlf"; } diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 355fc49..45653b2 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -34,18 +34,17 @@ - - - + + @@ -164,5 +163,9 @@ + + + +