Open PRGfx opened 3 years ago
It would also be cool to have the option too create a new translation file from the context menu
With a small .xlf
skeleton.
@PRGfx @crydotsnake If you're brave enough, you might try this version: https://plugins.jetbrains.com/plugin/9362-neos-support/edit/versions/eap/550359
This adds a context menu action for nodetypes "Translate NodeType". You'll need to configure your locales first. The action should trigger a notification with a link to the settings page.
Best if you backup your files before.
Thank you for your work @cvette! I installed 1.22.0-eap.2
now.
i18n
, however the translation file does not contain translationsproduct-name
needs to match the node-type namespace, not necessarily the containing packagetarget-language=".."
attribute)The IDE logged an exception.
java.lang.ArrayIndexOutOfBoundsException: Array index out of range: 0
at java.base/java.util.Vector.get(Vector.java:750)
at de.vette.idea.neos.actions.TranslateNodeTypeAction.extractNodeType(TranslateNodeTypeAction.java:161)
at de.vette.idea.neos.actions.TranslateNodeTypeAction.actionPerformed(TranslateNodeTypeAction.java:68)
at com.intellij.openapi.actionSystem.ex.ActionUtil.doPerformActionOrShowPopup(ActionUtil.kt:304)
at com.intellij.openapi.actionSystem.ex.ActionUtil.performActionDumbAwareWithCallbacks$lambda$4(ActionUtil.kt:275)
at com.intellij.openapi.actionSystem.impl.ActionManagerImpl.performWithActionCallbacks(ActionManagerImpl.kt:1161)
at com.intellij.openapi.actionSystem.ex.ActionUtil.performActionDumbAwareWithCallbacks(ActionUtil.kt:274)
at com.intellij.openapi.actionSystem.impl.ActionMenuItem.performAction$lambda$5(ActionMenuItem.kt:269)
at com.intellij.openapi.wm.impl.FocusManagerImpl.runOnOwnContext(FocusManagerImpl.java:227)
at com.intellij.openapi.actionSystem.impl.ActionMenuItem.performAction(ActionMenuItem.kt:260)
at com.intellij.openapi.actionSystem.impl.ActionMenuItem._init_$lambda$0(ActionMenuItem.kt:71)
at java.desktop/javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1972)
at com.intellij.openapi.actionSystem.impl.ActionMenuItem.fireActionPerformed$lambda$4(ActionMenuItem.kt:102)
at com.intellij.openapi.application.TransactionGuardImpl.performActivity(TransactionGuardImpl.java:106)
at com.intellij.openapi.application.TransactionGuardImpl.performUserActivity(TransactionGuardImpl.java:95)
at com.intellij.openapi.actionSystem.impl.ActionMenuItem.fireActionPerformed(ActionMenuItem.kt:101)
at com.intellij.ui.plaf.beg.BegMenuItemUI.doClick(BegMenuItemUI.java:525)
at com.intellij.ui.plaf.beg.BegMenuItemUI$MyMouseInputHandler.mouseReleased(BegMenuItemUI.java:558)
at java.desktop/java.awt.Component.processMouseEvent(Component.java:6657)
at java.desktop/javax.swing.JComponent.processMouseEvent(JComponent.java:3385)
at java.desktop/java.awt.Component.processEvent(Component.java:6422)
at java.desktop/java.awt.Container.processEvent(Container.java:2266)
at java.desktop/java.awt.Component.dispatchEventImpl(Component.java:5027)
at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2324)
at java.desktop/java.awt.Component.dispatchEvent(Component.java:4855)
at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4969)
at java.desktop/java.awt.LightweightDispatcher.processMouseEvent(Container.java:4583)
at java.desktop/java.awt.LightweightDispatcher.dispatchEvent(Container.java:4524)
at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2310)
at java.desktop/java.awt.Window.dispatchEventImpl(Window.java:2809)
at java.desktop/java.awt.Component.dispatchEvent(Component.java:4855)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:794)
at java.desktop/java.awt.EventQueue$3.run(EventQueue.java:739)
at java.desktop/java.awt.EventQueue$3.run(EventQueue.java:733)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:97)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:766)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:764)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:763)
at com.intellij.ide.IdeEventQueue.defaultDispatchEvent(IdeEventQueue.kt:699)
at com.intellij.ide.IdeEventQueue.dispatchMouseEvent(IdeEventQueue.kt:638)
at com.intellij.ide.IdeEventQueue._dispatchEvent$lambda$10(IdeEventQueue.kt:584)
at com.intellij.openapi.application.impl.RwLockHolder.runWithEnabledImplicitRead(RwLockHolder.kt:138)
at com.intellij.openapi.application.impl.RwLockHolder.runWithImplicitRead(RwLockHolder.kt:129)
at com.intellij.ide.IdeEventQueue._dispatchEvent(IdeEventQueue.kt:584)
at com.intellij.ide.IdeEventQueue.access$_dispatchEvent(IdeEventQueue.kt:77)
at com.intellij.ide.IdeEventQueue$dispatchEvent$processEventRunnable$1$1$1.compute(IdeEventQueue.kt:362)
at com.intellij.ide.IdeEventQueue$dispatchEvent$processEventRunnable$1$1$1.compute(IdeEventQueue.kt:361)
at com.intellij.openapi.progress.impl.CoreProgressManager.computePrioritized(CoreProgressManager.java:843)
at com.intellij.ide.IdeEventQueue$dispatchEvent$processEventRunnable$1$1.invoke(IdeEventQueue.kt:361)
at com.intellij.ide.IdeEventQueue$dispatchEvent$processEventRunnable$1$1.invoke(IdeEventQueue.kt:356)
at com.intellij.ide.IdeEventQueueKt.performActivity$lambda$1(IdeEventQueue.kt:1022)
at com.intellij.openapi.application.TransactionGuardImpl.performActivity(TransactionGuardImpl.java:114)
at com.intellij.ide.IdeEventQueueKt.performActivity(IdeEventQueue.kt:1022)
at com.intellij.ide.IdeEventQueue.dispatchEvent$lambda$7(IdeEventQueue.kt:356)
at com.intellij.openapi.application.impl.RwLockHolder.runIntendedWriteActionOnCurrentThread(RwLockHolder.kt:209)
at com.intellij.openapi.application.impl.ApplicationImpl.runIntendedWriteActionOnCurrentThread(ApplicationImpl.java:830)
at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.kt:398)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:207)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:128)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:117)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:113)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:105)
at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:92)
(Many other plugins throw this error, so probably not relevant:)
com.intellij.diagnostic.PluginException: `ActionUpdateThread.OLD_EDT` is deprecated and going to be removed soon. 'de.vette.idea.neos.actions.TranslateNodeTypeAction' must override `getActionUpdateThread()` and chose EDT or BGT. See ActionUpdateThread javadoc. [Plugin: vette.neos]
at com.intellij.diagnostic.PluginProblemReporterImpl.createPluginExceptionByClass(PluginProblemReporterImpl.java:23)
at com.intellij.diagnostic.PluginException.createByClass(PluginException.java:90)
at com.intellij.diagnostic.PluginException.reportDeprecatedUsage(PluginException.java:125)
at com.intellij.openapi.actionSystem.ActionUpdateThreadAware.getActionUpdateThread(ActionUpdateThreadAware.java:21)
at com.intellij.openapi.actionSystem.AnAction.getActionUpdateThread(AnAction.java:199)
There are some edge-cases with overrides, I think.
# My.NodeTypes/Configuration/NodeTypes.Base.yaml
My.NodeTypes:Text:
ui:
label: i18n # My.NodeTypes:NodeTypes.Text:ui.label
# My.Website/Configuration/NodeTypes.Overrides.Base.yaml
My.NodeTypes:Text:
ui:
label: i18n # overriding a single label in the distribution is realsitic
help:
message: i18n # alternatively add a new label to the existing nodetype
# everything here is My.NodeTypes:NodeTypes.Text:ui.label etc. (regardless of package where _this_ file is)
My.Website:Text
superTypes:
My.NodeTypes:Text: true
# tweak behavior, add additional properties
# this might have a label of My.NodeTypes:NodeTypes.Text:ui.label, but My.Website:NodeTypes.Text:properties... etc.
# however if a property is "redeclared" (i.e. we have a new ui.label=i18n), the label from the My.Website package would be used
This setup with the overrides probably isn't realistic like this, but both approaches individually make sense to me.
As both nodetypes in this scenario have the same name, afaik we could have
<xliff ...>
<file product-name="My.NodeTypes" ...></file>
<file product-name="My.Website" ...></file>
</xliff>
From what I understand, they could reside in different xlf files, as long as the file[original]
matches the original/expected filename (not sure how this works with nested directories, i.e. NodeTypes/Overrides.Test.xlf
+ original="Test"
vs original="NodeTypes/Test"
vs. Overrides/Test.xlf
+ `original="NodeTypes/Test" etc.)
https://flowframework.readthedocs.io/en/stable/TheDefinitiveGuide/PartIII/Internationalization.html#xliff-file-overrides
I tried v1.22.0-eap.3
and it generated multiple translation files for multiple node-types and the settings link in the notification did work, but the translation files were still empty. No further exceptions logged.
For my testing I was working in DistributionPackages/*/Configuration/*
, so not in the symlinked location and not with the nodetypes directory, if that helps.
Thanks for your detailed feedback!
For my testing I was working in
DistributionPackages/*/Configuration/*
, so not in the symlinked location and not with the nodetypes directory, if that helps.
This doesn't seem to be the issue. At least I wasn't able to reproduce it this way.
I suspect the problem occurs somewhere in this method: https://github.com/cvette/intellij-neos/blob/main/src/main/java/de/vette/idea/neos/actions/TranslateNodeTypeAction.java#L373C18-L373C46
Do you have any additional plugins installed that might handle XLIFF files? Would you be able to debug this further? That would help a lot.
Phew, that was quite a journey... in the end it turned out that apparently I registered *.xlf
as "XML" file-type before and it was then not categorized for your custom "Neos XLIFF" file type (that only included *.xliff
).
In turn the file was not "found" when searching for the XliffDomElement
and the fileElement
was null.
Changing the file-type association brings the plugin to life :+1:
However, I don't know if this happened automatically, based on a suggested action, as the file "looks like" XML or because of a plugin that might have come and gone since. So I could imagine, that others might be affected as well – maybe the take-away is only a troubleshooting info in the README.
When creating translated node-types I often find myself writing down the definition with all the "i18n" labels and later open both the node-type and a translation file side-by-side to see which strings I need – sometimes trying to remember what that label of the node-creation-dialog label was etc.
I think it would be really handy to have a context action on node-type definitions to generate xlf files, maybe even on a "label"-basis.
For each language (i.e. folder in Resources/Private/Translations) it would create a file based on the node-type name and stub all properties etc. (e.g. everything with "label: i18n" (or
help.message
,formatting.placeholder
etc.) and a "mappable" path (i.e. we know how to mapui.label
,properties.*.ui.label
etc. but would maybe ignore other paths).The default-language could be configurable in the plugin settings. Maybe it would make sense to have the stub configurable as well.
I recognize that it's more difficult to update a translation file (i.e. reading the XML and writing it back - in the best case while preserving comments or whitespaces). If that would be possible however, it would be a cool context-action to of course just update the translation file and "extract a string" into a translation. In any case I think it might be possible to get the "content" of
/xliff/file/body
as string, write it back and appendtrans-unit
s for new properties/translatables if no matchingtrans-unit
id
was found in the file.