Giter Site home page Giter Site logo

marhali / easy-i18n Goto Github PK

View Code? Open in Web Editor NEW
78.0 2.0 24.0 1.42 MB

This is a IntelliJ IDE based plugin for internationalization. Supports the most common translation file types.

License: MIT License

Java 100.00%
intellij intellij-plugin i18n webapp resource-bundles internationalization plugin translation json yaml

easy-i18n's Introduction

Build Version Downloads Donate


This is a plugin for easier management of translation files for projects that need to be translated into different languages. Translating large projects has never been so easy with your favorite IDE!

This plugin can be used for any project based on one of the formats and structures listed below.

Features

  • UI Tool-Window which supports tree-view and table-view
  • Easily Add / Edit / Delete translations
  • Filter all translations with full-text-search support
  • Editor Assistance: translation intention, completion-contributor, key-annotation and -folding
  • Translation key sorting and nesting can be configured
  • Extensive configuration options: locales directory, preferred locale, key delimiters
  • Missing language translations will be indicated red
  • Automatically reloads translation data if any locale file was changed

Builtin Support

File Types

JSON - JSON5 - YAML - Properties

Folder Structure

  • Single Directory: All translation files are within one directory
  • Modularized (Locale \ Namespace)
  • Modularized (Namespace \ Locale)

Language Support

JavaScript / TypeScript - Vue - Java - Kotlin - PHP

Installation

  • Using IDE built-in plugin system:

    Settings/Preferences > Plugins > Marketplace > Search for "easy-i18n" > Install Plugin

  • Manually:

    Download the latest release and install it manually using Settings/Preferences > Plugins > ⚙️ > Install plugin from disk...

Configuration

  • Install plugin. See Installation section
  • Create a directory that will contain all translation files
  • Create your individual translation files (e.g. en.json, de.json). See examples if you need assistance.
  • Click on the Settings action inside the EasyI18n Tool-Window (View > Tool Windows > Easy I18n)
  • Specify locales directory
  • Select folder structure and file parser to apply to your translation files
  • Translations can now be created / edited or deleted

Screenshots

Tree View TableView KeyCompletion KeyAnnotation KeyEdit Settings

For more examples, please refer to the Examples Directory.

Roadmap

  • JSON5 Support
  • Configurable namespace and section separators
  • Define default namespace to use if none was provided
  • Enhance editor code assistance
  • XML Support
  • Mark duplicate translation values
  • Python language assistance

See the open issues for a full list of proposed features (and known issues).

Contributing

Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are greatly appreciated.

If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement". Don't forget to give the project a star! Thanks again!

  1. Fork the Project
  2. Create your Feature Branch (git checkout -b feature/AmazingFeature)
  3. Commit your Changes (git commit -m 'Add some AmazingFeature')
  4. Push to the Branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

License

Distributed under the MIT License. See LICENSE for more information.

Contact

Marcel Haßlinger - @marhali_de - Portfolio Website

Project Link: https://github.com/marhali/easy-i18n

Donation

If the project helps you to reduce development time, you can give me a cup of coffee :)


Plugin based on the IntelliJ Platform Plugin Template.

easy-i18n's People

Contributors

actions-user avatar dependabot[bot] avatar jpilson avatar marhali avatar simulatan avatar sunarya-thito avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

easy-i18n's Issues

IDE Error Report

Additional information

null

Exception trace

null

java.lang.IndexOutOfBoundsException: Index 281 out of bounds for length 3
	at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:64)
	at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:70)
	at java.base/jdk.internal.util.Preconditions.checkIndex(Preconditions.java:248)
	at java.base/java.util.Objects.checkIndex(Objects.java:372)
	at java.base/java.util.ArrayList.get(ArrayList.java:459)
	at de.marhali.easyi18n.tabs.mapper.TableModelMapper.getValueAt(TableModelMapper.java:117)
	at java.desktop/javax.swing.JTable.getValueAt(JTable.java:2706)
	at de.marhali.easyi18n.action.AddAction.detectPreKey(AddAction.java:60)
	at de.marhali.easyi18n.action.AddAction.actionPerformed(AddAction.java:35)
	at com.intellij.openapi.actionSystem.impl.ActionButton.actionPerformed(ActionButton.java:178)
	at com.intellij.openapi.actionSystem.impl.ActionButton.lambda$performAction$0(ActionButton.java:154)
	at com.intellij.openapi.actionSystem.ex.ActionUtil.performDumbAwareWithCallbacks(ActionUtil.java:260)
	at com.intellij.openapi.actionSystem.impl.ActionButton.performAction(ActionButton.java:154)
	at com.intellij.openapi.actionSystem.impl.ActionButton.processMouseEvent(ActionButton.java:449)
	at java.desktop/java.awt.Component.processEvent(Component.java:6419)
	at java.desktop/java.awt.Container.processEvent(Container.java:2263)
	at java.desktop/java.awt.Component.dispatchEventImpl(Component.java:5029)
	at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2321)
	at java.desktop/java.awt.Component.dispatchEvent(Component.java:4861)
	at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4918)
	at java.desktop/java.awt.LightweightDispatcher.processMouseEvent(Container.java:4547)
	at java.desktop/java.awt.LightweightDispatcher.dispatchEvent(Container.java:4488)
	at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2307)
	at java.desktop/java.awt.Window.dispatchEventImpl(Window.java:2790)
	at java.desktop/java.awt.Component.dispatchEvent(Component.java:4861)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:778)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:727)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:95)
	at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:751)
	at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:749)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
	at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:748)
	at com.intellij.ide.IdeEventQueue.defaultDispatchEvent(IdeEventQueue.java:891)
	at com.intellij.ide.IdeEventQueue.dispatchMouseEvent(IdeEventQueue.java:820)
	at com.intellij.ide.IdeEventQueue._dispatchEvent(IdeEventQueue.java:757)
	at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$6(IdeEventQueue.java:447)
	at com.intellij.openapi.progress.impl.CoreProgressManager.computePrioritized(CoreProgressManager.java:818)
	at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$7(IdeEventQueue.java:446)
	at com.intellij.openapi.application.impl.ApplicationImpl.runIntendedWriteActionOnCurrentThread(ApplicationImpl.java:805)
	at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.java:498)
	at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
	at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)

IDE Error Report

Additional information

i have the files in a single folder, (es: en.json, fr.json)

Exception trace

An error occurred while processing translation files.
Config: SINGLE => JSON (.)
Path: /Users/albertobortolato/Documents/infiteplay/ipdoor-front-end/public/locales
Please check examples at https://github.com/marhali/easy-i18n before reporting an issue!

java.io.IOException: TranslationFile{virtualFile=file:///Users/albertobortolato/Documents/infiteplay/ipdoor-front-end/public/locales/.DS_Store, locale='', namespace='null'}

Expected a com.google.gson.JsonObject but was com.google.gson.JsonPrimitive
	at de.marhali.easyi18n.io.IOHandler.read(IOHandler.java:68)
	at de.marhali.easyi18n.DataStore.lambda$loadFromPersistenceLayer$0(DataStore.java:56)
	at com.intellij.openapi.application.impl.ApplicationImpl.runReadAction(ApplicationImpl.java:839)
	at de.marhali.easyi18n.DataStore.loadFromPersistenceLayer(DataStore.java:54)
	at de.marhali.easyi18n.action.ReloadAction.actionPerformed(ReloadAction.java:27)
	at com.intellij.openapi.actionSystem.impl.ActionButton.actionPerformed(ActionButton.java:178)
	at com.intellij.openapi.actionSystem.impl.ActionButton.lambda$performAction$0(ActionButton.java:154)
	at com.intellij.openapi.actionSystem.ex.ActionUtil.performDumbAwareWithCallbacks(ActionUtil.java:265)
	at com.intellij.openapi.actionSystem.impl.ActionButton.performAction(ActionButton.java:154)
	at com.intellij.openapi.actionSystem.impl.ActionButton.processMouseEvent(ActionButton.java:449)
	at java.desktop/java.awt.Component.processEvent(Component.java:6419)
	at java.desktop/java.awt.Container.processEvent(Container.java:2263)
	at java.desktop/java.awt.Component.dispatchEventImpl(Component.java:5029)
	at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2321)
	at java.desktop/java.awt.Component.dispatchEvent(Component.java:4861)
	at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4918)
	at java.desktop/java.awt.LightweightDispatcher.processMouseEvent(Container.java:4547)
	at java.desktop/java.awt.LightweightDispatcher.dispatchEvent(Container.java:4488)
	at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2307)
	at java.desktop/java.awt.Window.dispatchEventImpl(Window.java:2790)
	at java.desktop/java.awt.Component.dispatchEvent(Component.java:4861)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:778)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:727)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:95)
	at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:751)
	at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:749)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
	at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:748)
	at com.intellij.ide.IdeEventQueue.defaultDispatchEvent(IdeEventQueue.java:891)
	at com.intellij.ide.IdeEventQueue.dispatchMouseEvent(IdeEventQueue.java:820)
	at com.intellij.ide.IdeEventQueue._dispatchEvent(IdeEventQueue.java:757)
	at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$6(IdeEventQueue.java:447)
	at com.intellij.openapi.progress.impl.CoreProgressManager.computePrioritized(CoreProgressManager.java:818)
	at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$7(IdeEventQueue.java:446)
	at com.intellij.openapi.application.impl.ApplicationImpl.runIntendedWriteActionOnCurrentThread(ApplicationImpl.java:805)
	at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.java:498)
	at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
	at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
Caused by: com.google.gson.JsonSyntaxException: Expected a com.google.gson.JsonObject but was com.google.gson.JsonPrimitive
	at com.google.gson.internal.bind.TypeAdapters$35$1.read(TypeAdapters.java:911)
	at com.google.gson.Gson.fromJson(Gson.java:932)
	at com.google.gson.Gson.fromJson(Gson.java:870)
	at de.marhali.easyi18n.io.parser.json.JsonParserStrategy.read(JsonParserStrategy.java:38)
	at de.marhali.easyi18n.io.IOHandler.read(IOHandler.java:66)
	... 45 more

IDE Error Report

Additional information

null

Exception trace

An error occurred while processing translation files.
Config: SINGLE => JSON (.)
Path: C:\Users\Mohamad_ka\WebstormProjects\iRole-Express-Admin\resource\lang
Please check examples at https://github.com/marhali/easy-i18n before reporting an issue!

java.io.IOException: TranslationFile{virtualFile=file://C:/Users/Mohamad_ka/WebstormProjects/iRole-Express-Admin/resource/lang/en.json, locale='en', namespace='null'}

java.io.EOFException: End of input at line 87 column 1 path $.typeScript
	at de.marhali.easyi18n.io.IOHandler.read(IOHandler.java:69)
	at de.marhali.easyi18n.DataStore.lambda$loadFromPersistenceLayer$0(DataStore.java:57)
	at com.intellij.openapi.application.impl.ApplicationImpl.runReadAction(ApplicationImpl.java:839)
	at de.marhali.easyi18n.DataStore.loadFromPersistenceLayer(DataStore.java:55)
	at de.marhali.easyi18n.action.ReloadAction.actionPerformed(ReloadAction.java:27)
	at com.intellij.openapi.actionSystem.impl.ActionButton.actionPerformed(ActionButton.java:172)
	at com.intellij.openapi.actionSystem.impl.ActionButton.lambda$performAction$0(ActionButton.java:151)
	at com.intellij.openapi.actionSystem.ex.ActionUtil.performDumbAwareWithCallbacks(ActionUtil.java:265)
	at com.intellij.openapi.actionSystem.impl.ActionButton.performAction(ActionButton.java:151)
	at com.intellij.openapi.actionSystem.impl.ActionButton.processMouseEvent(ActionButton.java:433)
	at java.desktop/java.awt.Component.processEvent(Component.java:6419)
	at java.desktop/java.awt.Container.processEvent(Container.java:2263)
	at java.desktop/java.awt.Component.dispatchEventImpl(Component.java:5029)
	at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2321)
	at java.desktop/java.awt.Component.dispatchEvent(Component.java:4861)
	at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4918)
	at java.desktop/java.awt.LightweightDispatcher.processMouseEvent(Container.java:4547)
	at java.desktop/java.awt.LightweightDispatcher.dispatchEvent(Container.java:4488)
	at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2307)
	at java.desktop/java.awt.Window.dispatchEventImpl(Window.java:2790)
	at java.desktop/java.awt.Component.dispatchEvent(Component.java:4861)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:778)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:727)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:95)
	at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:751)
	at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:749)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
	at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:748)
	at com.intellij.ide.IdeEventQueue.defaultDispatchEvent(IdeEventQueue.java:891)
	at com.intellij.ide.IdeEventQueue.dispatchMouseEvent(IdeEventQueue.java:820)
	at com.intellij.ide.IdeEventQueue._dispatchEvent(IdeEventQueue.java:757)
	at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$6(IdeEventQueue.java:447)
	at com.intellij.openapi.progress.impl.CoreProgressManager.computePrioritized(CoreProgressManager.java:818)
	at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$7(IdeEventQueue.java:446)
	at com.intellij.openapi.application.impl.ApplicationImpl.runIntendedWriteActionOnCurrentThread(ApplicationImpl.java:805)
	at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.java:498)
	at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
	at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
Caused by: com.google.gson.JsonSyntaxException: java.io.EOFException: End of input at line 87 column 1 path $.typeScript
	at com.google.gson.Gson.fromJson(Gson.java:942)
	at com.google.gson.Gson.fromJson(Gson.java:870)
	at de.marhali.easyi18n.io.parser.json.JsonParserStrategy.read(JsonParserStrategy.java:38)
	at de.marhali.easyi18n.io.IOHandler.read(IOHandler.java:67)
	... 45 more
Caused by: java.io.EOFException: End of input at line 87 column 1 path $.typeScript
	at com.google.gson.stream.JsonReader.nextNonWhitespace(JsonReader.java:1395)
	at com.google.gson.stream.JsonReader.doPeek(JsonReader.java:481)
	at com.google.gson.stream.JsonReader.hasNext(JsonReader.java:413)
	at com.google.gson.internal.bind.TypeAdapters$29.read(TypeAdapters.java:725)
	at com.google.gson.internal.bind.TypeAdapters$29.read(TypeAdapters.java:701)
	at com.google.gson.internal.bind.TypeAdapters$35$1.read(TypeAdapters.java:908)
	at com.google.gson.Gson.fromJson(Gson.java:932)
	... 48 more

Sorting and formating JSON's

When I'm deleting some key or editing it in plugin window it sorting JSON keys alphabetily, removes quotes that surrounds numbers, can you add please option to not to change this ? I really appreciate for extention, but this thing very annoying, thx!

UTF-8 properties files

Properties files are typically encoded in a "simple" ASCII format and unicode characters are escaped.
However, I have a custom plugin to use properties files with Unity3D. Thereby the properties files are encoded as UTF-8 for simplicity (it is simpler for me when working with other text editors, when searching, etc.).

I noticed that Easy-i18n is changing the UTF-8 encoded characters in my files to the escaped version. Example: ü becomes \u00FC

Is there an option to use UTF-8 instead?

1.6 is not working

Throw an expression about GSON type mismatch
I rolled back to 1.5.1 in the meantime (sorry don't have the time to reproduce and paste here the exception message)

npe: I18nKeyAnnotator

java.lang.NullPointerException at de.marhali.easyi18n.ui.editor.I18nKeyAnnotator.annotate(I18nKeyAnnotator.java:38) at com.intellij.codeInsight.daemon.impl.DefaultHighlightVisitor.runAnnotators(DefaultHighlightVisitor.java:136) at com.intellij.codeInsight.daemon.impl.DefaultHighlightVisitor.visit(DefaultHighlightVisitor.java:116) at com.intellij.codeInsight.daemon.impl.GeneralHighlightingPass.runVisitors(GeneralHighlightingPass.java:335) at com.intellij.codeInsight.daemon.impl.GeneralHighlightingPass.lambda$collectHighlights$5(GeneralHighlightingPass.java:268) at com.intellij.codeInsight.daemon.impl.GeneralHighlightingPass.analyzeByVisitors(GeneralHighlightingPass.java:294) at com.intellij.codeInsight.daemon.impl.GeneralHighlightingPass.lambda$analyzeByVisitors$6(GeneralHighlightingPass.java:297) at com.intellij.codeInsight.daemon.impl.analysis.XmlHighlightVisitor.analyze(XmlHighlightVisitor.java:603) at com.intellij.codeInsight.daemon.impl.GeneralHighlightingPass.analyzeByVisitors(GeneralHighlightingPass.java:297) at com.intellij.codeInsight.daemon.impl.GeneralHighlightingPass.lambda$analyzeByVisitors$6(GeneralHighlightingPass.java:297) at com.intellij.codeInsight.daemon.impl.DefaultHighlightVisitor.analyze(DefaultHighlightVisitor.java:96) at com.intellij.codeInsight.daemon.impl.GeneralHighlightingPass.analyzeByVisitors(GeneralHighlightingPass.java:297) at com.intellij.codeInsight.daemon.impl.GeneralHighlightingPass.collectHighlights(GeneralHighlightingPass.java:265) at com.intellij.codeInsight.daemon.impl.GeneralHighlightingPass.collectInformationWithProgress(GeneralHighlightingPass.java:211) at com.intellij.codeInsight.daemon.impl.ProgressableTextEditorHighlightingPass.doCollectInformation(ProgressableTextEditorHighlightingPass.java:84) at com.intellij.codeHighlighting.TextEditorHighlightingPass.collectInformation(TextEditorHighlightingPass.java:56) at com.intellij.codeInsight.daemon.impl.PassExecutorService$ScheduledPass.lambda$doRun$1(PassExecutorService.java:400) at com.intellij.openapi.application.impl.ApplicationImpl.tryRunReadAction(ApplicationImpl.java:1096) at com.intellij.codeInsight.daemon.impl.PassExecutorService$ScheduledPass.lambda$doRun$2(PassExecutorService.java:393) at com.intellij.openapi.progress.impl.CoreProgressManager.registerIndicatorAndRun(CoreProgressManager.java:688) at com.intellij.openapi.progress.impl.CoreProgressManager.executeProcessUnderProgress(CoreProgressManager.java:634) at com.intellij.openapi.progress.impl.ProgressManagerImpl.executeProcessUnderProgress(ProgressManagerImpl.java:64) at com.intellij.codeInsight.daemon.impl.PassExecutorService$ScheduledPass.doRun(PassExecutorService.java:392) at com.intellij.codeInsight.daemon.impl.PassExecutorService$ScheduledPass.lambda$run$0(PassExecutorService.java:368) at com.intellij.openapi.application.impl.ReadMostlyRWLock.executeByImpatientReader(ReadMostlyRWLock.java:167) at com.intellij.openapi.application.impl.ApplicationImpl.executeByImpatientReader(ApplicationImpl.java:178) at com.intellij.codeInsight.daemon.impl.PassExecutorService$ScheduledPass.run(PassExecutorService.java:366) at com.intellij.concurrency.JobLauncherImpl$VoidForkJoinTask$1.exec(JobLauncherImpl.java:188) at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290) at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1020) at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1656) at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1594) at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:183)

not working? or i have wrong settings

hi i have a project with a locales folder but i will not recognize the files they are json but i also need to keep the js files they just export the json but itlooks like its not working
image

thanks

Problems editing existing resource bundle

Hallo Marcel

nice plugin, but I'm having troubles using it with our (existing) project.

We already have a resource bundle of en.json, de.json, fr.json populated, and I would like to edit these with the plugin. File format is correct so far.

  • The plugin shows all existing keys red, and one column per language, but no values at all.
  • Adding an entry, it is inserted correctly into the files. key shows black (probably means "complete set of values"). I can further edit key and values, everything fine. It even sorts the entry correctly in between the red keys.
  • I'm not able to edit the red keys (right click has no effect), or set a value into the empty values (values are not kept)

Does the plugin somehow keep track of keys it has added itself? aatest added by plugin, looks good, but other keys are not handled / handled well.

{
  "aatest": "sdfg",
  "application.name": "My Application",
  "application.name.short": "App",
  "attribute.key": "Value"
}

-- edited for more example data

v1.5.0 NullPointerException - KeyAnnotator.java:34

Hi.

In last version of Webstorm with last version of Easy I18n (1.5.0) has

java.lang.NullPointerException
	at de.marhali.easyi18n.editor.KeyAnnotator.annotate(KeyAnnotator.java:34)
	at de.marhali.easyi18n.editor.generic.GenericKeyAnnotator.annotate(GenericKeyAnnotator.java:31)
	at com.intellij.codeInsight.daemon.impl.DefaultHighlightVisitor.runAnnotators(DefaultHighlightVisitor.java:134)
	at com.intellij.codeInsight.daemon.impl.DefaultHighlightVisitor.visit(DefaultHighlightVisitor.java:114)
	at com.intellij.codeInsight.daemon.impl.GeneralHighlightingPass.runVisitors(GeneralHighlightingPass.java:335)
	at com.intellij.codeInsight.daemon.impl.GeneralHighlightingPass.lambda$collectHighlights$5(GeneralHighlightingPass.java:268)
	at com.intellij.codeInsight.daemon.impl.GeneralHighlightingPass.analyzeByVisitors(GeneralHighlightingPass.java:294)
	at com.intellij.codeInsight.daemon.impl.GeneralHighlightingPass.lambda$analyzeByVisitors$6(GeneralHighlightingPass.java:297)
	at com.intellij.codeInsight.daemon.impl.analysis.XmlHighlightVisitor.analyze(XmlHighlightVisitor.java:605)
	at com.intellij.codeInsight.daemon.impl.GeneralHighlightingPass.analyzeByVisitors(GeneralHighlightingPass.java:297)
	at com.intellij.codeInsight.daemon.impl.GeneralHighlightingPass.lambda$analyzeByVisitors$6(GeneralHighlightingPass.java:297)
	at com.intellij.codeInsight.daemon.impl.DefaultHighlightVisitor.analyze(DefaultHighlightVisitor.java:94)
	at com.intellij.codeInsight.daemon.impl.GeneralHighlightingPass.analyzeByVisitors(GeneralHighlightingPass.java:297)
	at com.intellij.codeInsight.daemon.impl.GeneralHighlightingPass.lambda$analyzeByVisitors$6(GeneralHighlightingPass.java:297)
	at org.igu.plugins.bettercomments.visitor.DefaultCommentsVisitor.analyze(DefaultCommentsVisitor.kt:32)
	at com.intellij.codeInsight.daemon.impl.GeneralHighlightingPass.analyzeByVisitors(GeneralHighlightingPass.java:297)
	at com.intellij.codeInsight.daemon.impl.GeneralHighlightingPass.collectHighlights(GeneralHighlightingPass.java:265)
	at com.intellij.codeInsight.daemon.impl.GeneralHighlightingPass.collectInformationWithProgress(GeneralHighlightingPass.java:211)
	at com.intellij.codeInsight.daemon.impl.ProgressableTextEditorHighlightingPass.doCollectInformation(ProgressableTextEditorHighlightingPass.java:84)
	at com.intellij.codeHighlighting.TextEditorHighlightingPass.collectInformation(TextEditorHighlightingPass.java:56)
	at com.intellij.codeInsight.daemon.impl.PassExecutorService$ScheduledPass.lambda$doRun$1(PassExecutorService.java:414)
	at com.intellij.openapi.application.impl.ApplicationImpl.tryRunReadAction(ApplicationImpl.java:1078)
	at com.intellij.codeInsight.daemon.impl.PassExecutorService$ScheduledPass.lambda$doRun$2(PassExecutorService.java:407)
	at com.intellij.openapi.progress.impl.CoreProgressManager.registerIndicatorAndRun(CoreProgressManager.java:705)
	at com.intellij.openapi.progress.impl.CoreProgressManager.executeProcessUnderProgress(CoreProgressManager.java:647)
	at com.intellij.openapi.progress.impl.ProgressManagerImpl.executeProcessUnderProgress(ProgressManagerImpl.java:63)
	at com.intellij.codeInsight.daemon.impl.PassExecutorService$ScheduledPass.doRun(PassExecutorService.java:406)
	at com.intellij.codeInsight.daemon.impl.PassExecutorService$ScheduledPass.lambda$run$0(PassExecutorService.java:382)
	at com.intellij.openapi.application.impl.ReadMostlyRWLock.executeByImpatientReader(ReadMostlyRWLock.java:174)
	at com.intellij.openapi.application.impl.ApplicationImpl.executeByImpatientReader(ApplicationImpl.java:183)
	at com.intellij.codeInsight.daemon.impl.PassExecutorService$ScheduledPass.run(PassExecutorService.java:380)
	at com.intellij.concurrency.JobLauncherImpl$VoidForkJoinTask$1.exec(JobLauncherImpl.java:188)
	at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
	at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1020)
	at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1656)
	at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1594)
	at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:183)

IDE Error Report

Additional information

null

Exception trace

null

java.lang.IndexOutOfBoundsException: Index 345 out of bounds for length 4
	at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:64)
	at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:70)
	at java.base/jdk.internal.util.Preconditions.checkIndex(Preconditions.java:248)
	at java.base/java.util.Objects.checkIndex(Objects.java:372)
	at java.base/java.util.ArrayList.get(ArrayList.java:459)
	at de.marhali.easyi18n.tabs.mapper.TableModelMapper.getValueAt(TableModelMapper.java:117)
	at java.desktop/javax.swing.JTable.getValueAt(JTable.java:2706)
	at de.marhali.easyi18n.action.AddAction.detectPreKey(AddAction.java:60)
	at de.marhali.easyi18n.action.AddAction.actionPerformed(AddAction.java:35)
	at com.intellij.openapi.actionSystem.impl.ActionButton.actionPerformed(ActionButton.java:178)
	at com.intellij.openapi.actionSystem.impl.ActionButton.lambda$performAction$0(ActionButton.java:154)
	at com.intellij.openapi.actionSystem.ex.ActionUtil.performDumbAwareWithCallbacks(ActionUtil.java:260)
	at com.intellij.openapi.actionSystem.impl.ActionButton.performAction(ActionButton.java:154)
	at com.intellij.openapi.actionSystem.impl.ActionButton.processMouseEvent(ActionButton.java:449)
	at java.desktop/java.awt.Component.processEvent(Component.java:6419)
	at java.desktop/java.awt.Container.processEvent(Container.java:2263)
	at java.desktop/java.awt.Component.dispatchEventImpl(Component.java:5029)
	at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2321)
	at java.desktop/java.awt.Component.dispatchEvent(Component.java:4861)
	at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4918)
	at java.desktop/java.awt.LightweightDispatcher.processMouseEvent(Container.java:4547)
	at java.desktop/java.awt.LightweightDispatcher.dispatchEvent(Container.java:4488)
	at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2307)
	at java.desktop/java.awt.Window.dispatchEventImpl(Window.java:2790)
	at java.desktop/java.awt.Component.dispatchEvent(Component.java:4861)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:778)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:727)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:95)
	at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:751)
	at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:749)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
	at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:748)
	at com.intellij.ide.IdeEventQueue.defaultDispatchEvent(IdeEventQueue.java:891)
	at com.intellij.ide.IdeEventQueue.dispatchMouseEvent(IdeEventQueue.java:820)
	at com.intellij.ide.IdeEventQueue._dispatchEvent(IdeEventQueue.java:757)
	at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$6(IdeEventQueue.java:447)
	at com.intellij.openapi.progress.impl.CoreProgressManager.computePrioritized(CoreProgressManager.java:818)
	at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$7(IdeEventQueue.java:446)
	at com.intellij.openapi.application.impl.ApplicationImpl.runIntendedWriteActionOnCurrentThread(ApplicationImpl.java:805)
	at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.java:498)
	at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
	at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)

IDE Error Report

Additional information

null

Exception trace

null

com.intellij.serviceContainer.AlreadyDisposedException: Cannot create de.marhali.easyi18n.service.SettingsService because container is already disposed (container=Project(name=testTransloco, containerState=DISPOSE_COMPLETED, componentStore=/var/job/testTransloco) (disposed))
	at com.intellij.serviceContainer.ContainerUtilKt.throwAlreadyDisposedError(containerUtil.kt:34)
	at com.intellij.serviceContainer.ComponentManagerImpl.doGetService(ComponentManagerImpl.kt:617)
	at com.intellij.serviceContainer.ComponentManagerImpl.getService(ComponentManagerImpl.kt:569)
	at com.intellij.openapi.client.ClientAwareComponentManager.getFromSelfOrCurrentSession(ClientAwareComponentManager.kt:37)
	at com.intellij.openapi.client.ClientAwareComponentManager.getService(ClientAwareComponentManager.kt:22)
	at de.marhali.easyi18n.service.SettingsService.getInstance(SettingsService.java:19)
	at de.marhali.easyi18n.DataStore.loadFromPersistenceLayer(DataStore.java:51)
	at de.marhali.easyi18n.service.FileChangeListener$1.lambda$afterVfsChange$1(FileChangeListener.java:58)
	at java.base/java.lang.Iterable.forEach(Iterable.java:75)
	at de.marhali.easyi18n.service.FileChangeListener$1.afterVfsChange(FileChangeListener.java:54)
	at com.intellij.openapi.vfs.newvfs.AsyncEventSupport.afterVfsChange(AsyncEventSupport.java:133)
	at com.intellij.openapi.vfs.newvfs.AsyncEventSupport$1.after(AsyncEventSupport.java:65)
	at com.intellij.util.messages.impl.MessageBusImpl.invokeMethod(MessageBusImpl.java:645)
	at com.intellij.util.messages.impl.MessageBusImpl.invokeListener(MessageBusImpl.java:620)
	at com.intellij.util.messages.impl.MessageBusImpl.deliverMessage(MessageBusImpl.java:417)
	at com.intellij.util.messages.impl.MessageBusImpl.pumpWaitingBuses(MessageBusImpl.java:390)
	at com.intellij.util.messages.impl.MessageBusImpl.pumpMessages(MessageBusImpl.java:372)
	at com.intellij.util.messages.impl.MessageBusImpl.access$200(MessageBusImpl.java:33)
	at com.intellij.util.messages.impl.MessageBusImpl$MessagePublisher.invoke(MessageBusImpl.java:179)
	at com.sun.proxy.$Proxy179.after(Unknown Source)
	at com.intellij.openapi.vfs.newvfs.persistent.PersistentFSImpl.fireAfterEvents(PersistentFSImpl.java:1188)
	at com.intellij.openapi.vfs.newvfs.persistent.PersistentFSImpl$3.close(PersistentFSImpl.java:780)
	at com.intellij.openapi.vfs.newvfs.impl.VirtualFileImpl.setBinaryContent(VirtualFileImpl.java:159)
	at com.intellij.openapi.vfs.VirtualFile.setBinaryContent(VirtualFile.java:559)
	at com.intellij.openapi.vfs.VirtualFile.setBinaryContent(VirtualFile.java:555)
	at de.marhali.easyi18n.io.parser.json.JsonParserStrategy.write(JsonParserStrategy.java:53)
	at de.marhali.easyi18n.io.IOHandler.write(IOHandler.java:94)
	at de.marhali.easyi18n.DataStore.lambda$saveToPersistenceLayer$1(DataStore.java:83)
	at com.intellij.openapi.application.impl.ApplicationImpl.runWriteAction(ApplicationImpl.java:947)
	at de.marhali.easyi18n.DataStore.saveToPersistenceLayer(DataStore.java:81)
	at de.marhali.easyi18n.InstanceManager.processUpdate(InstanceManager.java:64)
	at de.marhali.easyi18n.dialog.AddDialog.saveTranslation(AddDialog.java:67)
	at de.marhali.easyi18n.dialog.AddDialog.showAndHandle(AddDialog.java:52)
	at de.marhali.easyi18n.action.AddAction.actionPerformed(AddAction.java:35)
	at com.intellij.openapi.actionSystem.impl.ActionButton.actionPerformed(ActionButton.java:172)
	at com.intellij.openapi.actionSystem.impl.ActionButton.lambda$performAction$0(ActionButton.java:151)
	at com.intellij.openapi.actionSystem.ex.ActionUtil.performDumbAwareWithCallbacks(ActionUtil.java:265)
	at com.intellij.openapi.actionSystem.impl.ActionButton.performAction(ActionButton.java:151)
	at com.intellij.openapi.actionSystem.impl.ActionButton.processMouseEvent(ActionButton.java:433)
	at java.desktop/java.awt.Component.processEvent(Component.java:6419)
	at java.desktop/java.awt.Container.processEvent(Container.java:2263)
	at java.desktop/java.awt.Component.dispatchEventImpl(Component.java:5029)
	at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2321)
	at java.desktop/java.awt.Component.dispatchEvent(Component.java:4861)
	at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4918)
	at java.desktop/java.awt.LightweightDispatcher.processMouseEvent(Container.java:4547)
	at java.desktop/java.awt.LightweightDispatcher.dispatchEvent(Container.java:4488)
	at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2307)
	at java.desktop/java.awt.Window.dispatchEventImpl(Window.java:2790)
	at java.desktop/java.awt.Component.dispatchEvent(Component.java:4861)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:778)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:727)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:95)
	at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:751)
	at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:749)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
	at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:748)
	at com.intellij.ide.IdeEventQueue.defaultDispatchEvent(IdeEventQueue.java:891)
	at com.intellij.ide.IdeEventQueue.dispatchMouseEvent(IdeEventQueue.java:820)
	at com.intellij.ide.IdeEventQueue._dispatchEvent(IdeEventQueue.java:757)
	at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$6(IdeEventQueue.java:447)
	at com.intellij.openapi.progress.impl.CoreProgressManager.computePrioritized(CoreProgressManager.java:818)
	at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$7(IdeEventQueue.java:446)
	at com.intellij.openapi.application.impl.ApplicationImpl.runIntendedWriteActionOnCurrentThread(ApplicationImpl.java:805)
	at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.java:498)
	at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
	at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)

Add option for user to choose which module logic to use

My logic for modularized json files is different compared to what is shown in the examples directory :

  • In example : locale = directory, module = file

— res
— — locale-de
— — —moduleA.json
— — — moduleB.json
— — locale-en
— — — moduleA.json
— — — moduleB.json

  • In my project : locale = file, module = directory

— res
— —moduleA
— — —de.json
— — —en.json
— —moduleB
— — —de.json
— — —en.json

It could be nice to have a toggle in the plugin settings, so then we can choose which module logic we want to use.

Enhance internal data structure

Before we can successfully implement XML file type we should enhance our internal data structure to support all different translation types. Right now we only support simple key <=> value translations without any additional logic.

So what should be added?

  • Support pluralization
  • Support context
  • Provide description to translations
  • Mark message parts that should not be translated

(includes some parts of #93)

Problems that need to be considered

Usage in editor

  • Vue and React uses different formats for pluralization

EasyI18n Editor

  • How do we want to easily handle those parts inside our GUI
  • We should improve array handling in GUI

TableView scrolls to bottom after edit

After closing a modal after editing a translation the TableView always scrolls to the bottom. Making it nearly unable to use, as you have to scroll back up and find the translation in the list after each edit.

IDE Error Report

Additional information

null

Exception trace

null

com.intellij.serviceContainer.AlreadyDisposedException: Cannot create de.marhali.easyi18n.service.SettingsService because container is already disposed (container=Project(name=x2a_front, containerState=DISPOSE_COMPLETED, componentStore=D:\x2a\x2a_front) (disposed))
	at com.intellij.serviceContainer.ContainerUtilKt.throwAlreadyDisposedError(containerUtil.kt:34)
	at com.intellij.serviceContainer.ComponentManagerImpl.doGetService(ComponentManagerImpl.kt:617)
	at com.intellij.serviceContainer.ComponentManagerImpl.getService(ComponentManagerImpl.kt:569)
	at com.intellij.openapi.client.ClientAwareComponentManager.getFromSelfOrCurrentSession(ClientAwareComponentManager.kt:37)
	at com.intellij.openapi.client.ClientAwareComponentManager.getService(ClientAwareComponentManager.kt:22)
	at de.marhali.easyi18n.service.SettingsService.getInstance(SettingsService.java:19)
	at de.marhali.easyi18n.DataStore.loadFromPersistenceLayer(DataStore.java:51)
	at de.marhali.easyi18n.service.FileChangeListener$1.lambda$afterVfsChange$1(FileChangeListener.java:58)
	at java.base/java.lang.Iterable.forEach(Iterable.java:75)
	at de.marhali.easyi18n.service.FileChangeListener$1.afterVfsChange(FileChangeListener.java:54)
	at com.intellij.openapi.vfs.newvfs.AsyncEventSupport.afterVfsChange(AsyncEventSupport.java:133)
	at com.intellij.openapi.vfs.newvfs.AsyncEventSupport$1.after(AsyncEventSupport.java:65)
	at com.intellij.util.messages.impl.MessageBusImpl.invokeMethod(MessageBusImpl.java:645)
	at com.intellij.util.messages.impl.MessageBusImpl.invokeListener(MessageBusImpl.java:620)
	at com.intellij.util.messages.impl.MessageBusImpl.deliverMessage(MessageBusImpl.java:417)
	at com.intellij.util.messages.impl.MessageBusImpl.pumpWaitingBuses(MessageBusImpl.java:390)
	at com.intellij.util.messages.impl.MessageBusImpl.pumpMessages(MessageBusImpl.java:372)
	at com.intellij.util.messages.impl.MessageBusImpl.access$200(MessageBusImpl.java:33)
	at com.intellij.util.messages.impl.MessageBusImpl$MessagePublisher.invoke(MessageBusImpl.java:179)
	at com.sun.proxy.$Proxy163.after(Unknown Source)
	at com.intellij.openapi.vfs.newvfs.persistent.PersistentFSImpl.fireAfterEvents(PersistentFSImpl.java:1188)
	at com.intellij.openapi.vfs.newvfs.persistent.PersistentFSImpl$3.close(PersistentFSImpl.java:780)
	at com.intellij.openapi.vfs.newvfs.impl.VirtualFileImpl.setBinaryContent(VirtualFileImpl.java:159)
	at com.intellij.openapi.vfs.VirtualFile.setBinaryContent(VirtualFile.java:559)
	at com.intellij.openapi.vfs.VirtualFile.setBinaryContent(VirtualFile.java:555)
	at de.marhali.easyi18n.io.parser.json.JsonParserStrategy.write(JsonParserStrategy.java:53)
	at de.marhali.easyi18n.io.IOHandler.write(IOHandler.java:94)
	at de.marhali.easyi18n.DataStore.lambda$saveToPersistenceLayer$1(DataStore.java:83)
	at com.intellij.openapi.application.impl.ApplicationImpl.runWriteAction(ApplicationImpl.java:947)
	at de.marhali.easyi18n.DataStore.saveToPersistenceLayer(DataStore.java:81)
	at de.marhali.easyi18n.InstanceManager.processUpdate(InstanceManager.java:64)
	at de.marhali.easyi18n.dialog.EditDialog.showAndHandle(EditDialog.java:45)
	at de.marhali.easyi18n.tabs.TreeView.showEditPopup(TreeView.java:136)
	at de.marhali.easyi18n.tabs.TreeView.lambda$new$0(TreeView.java:57)
	at de.marhali.easyi18n.listener.PopupClickListener.mouseReleased(PopupClickListener.java:33)
	at java.desktop/java.awt.AWTEventMulticaster.mouseReleased(AWTEventMulticaster.java:298)
	at java.desktop/java.awt.Component.processMouseEvent(Component.java:6654)
	at java.desktop/javax.swing.JComponent.processMouseEvent(JComponent.java:3345)
	at com.intellij.ui.treeStructure.Tree.processMouseEvent(Tree.java:394)
	at java.desktop/java.awt.Component.processEvent(Component.java:6419)
	at java.desktop/java.awt.Container.processEvent(Container.java:2263)
	at java.desktop/java.awt.Component.dispatchEventImpl(Component.java:5029)
	at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2321)
	at java.desktop/java.awt.Component.dispatchEvent(Component.java:4861)
	at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4918)
	at java.desktop/java.awt.LightweightDispatcher.processMouseEvent(Container.java:4547)
	at java.desktop/java.awt.LightweightDispatcher.dispatchEvent(Container.java:4488)
	at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2307)
	at java.desktop/java.awt.Window.dispatchEventImpl(Window.java:2790)
	at java.desktop/java.awt.Component.dispatchEvent(Component.java:4861)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:778)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:727)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:95)
	at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:751)
	at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:749)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
	at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:748)
	at com.intellij.ide.IdeEventQueue.defaultDispatchEvent(IdeEventQueue.java:891)
	at com.intellij.ide.IdeEventQueue.dispatchMouseEvent(IdeEventQueue.java:820)
	at com.intellij.ide.IdeEventQueue._dispatchEvent(IdeEventQueue.java:757)
	at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$6(IdeEventQueue.java:447)
	at com.intellij.openapi.progress.impl.CoreProgressManager.computePrioritized(CoreProgressManager.java:818)
	at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$7(IdeEventQueue.java:446)
	at com.intellij.openapi.application.impl.ApplicationImpl.runIntendedWriteActionOnCurrentThread(ApplicationImpl.java:805)
	at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.java:498)
	at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
	at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)

Consider supporting JSON5

The library I use (VueI18n) supports the JSON5 format (a no-nonsensical JSON format that is actually made for humans), so it would be really nice if this extension could support reading and editing JSON5 files :)
https://json5.org/

IDE Error Report

Additional information

null

Exception trace

An error occurred while processing translation files.
Config: SINGLE => JSON (.)
Path: null
Please check examples at https://github.com/marhali/easy-i18n before reporting an issue!

java.lang.IllegalArgumentException: Locales path must not be empty
	at de.marhali.easyi18n.io.IOHandler.read(IOHandler.java:52)
	at de.marhali.easyi18n.DataStore.lambda$loadFromPersistenceLayer$0(DataStore.java:56)
	at com.intellij.openapi.application.impl.ApplicationImpl.runReadAction(ApplicationImpl.java:828)
	at de.marhali.easyi18n.DataStore.loadFromPersistenceLayer(DataStore.java:54)
	at de.marhali.easyi18n.InstanceManager.lambda$new$1(InstanceManager.java:41)
	at com.intellij.openapi.application.TransactionGuardImpl.runWithWritingAllowed(TransactionGuardImpl.java:214)
	at com.intellij.openapi.application.TransactionGuardImpl.access$200(TransactionGuardImpl.java:21)
	at com.intellij.openapi.application.TransactionGuardImpl$2.run(TransactionGuardImpl.java:196)
	at com.intellij.openapi.application.impl.ApplicationImpl.runIntendedWriteActionOnCurrentThread(ApplicationImpl.java:794)
	at com.intellij.openapi.application.impl.ApplicationImpl.lambda$invokeLater$4(ApplicationImpl.java:350)
	at com.intellij.openapi.application.impl.FlushQueue.doRun(FlushQueue.java:84)
	at com.intellij.openapi.application.impl.FlushQueue.runNextEvent(FlushQueue.java:133)
	at com.intellij.openapi.application.impl.FlushQueue.flushNow(FlushQueue.java:46)
	at com.intellij.openapi.application.impl.FlushQueue$FlushNow.run(FlushQueue.java:189)
	at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:313)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:776)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:727)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
	at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:746)
	at com.intellij.ide.IdeEventQueue.defaultDispatchEvent(IdeEventQueue.java:885)
	at com.intellij.ide.IdeEventQueue._dispatchEvent(IdeEventQueue.java:754)
	at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$6(IdeEventQueue.java:441)
	at com.intellij.openapi.progress.impl.CoreProgressManager.computePrioritized(CoreProgressManager.java:825)
	at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$7(IdeEventQueue.java:440)
	at com.intellij.openapi.application.impl.ApplicationImpl.runIntendedWriteActionOnCurrentThread(ApplicationImpl.java:794)
	at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.java:486)
	at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
	at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)

IDE Error Report

Additional information

null

Exception trace

An error occurred while processing translation files.
Config: SINGLE => JSON (.)
Path: /Users/daberkow/dev/Platform/frontend/src/translations
Please check examples at https://github.com/marhali/easy-i18n before reporting an issue!

java.io.IOException: TranslationFile{virtualFile=file:///Users/daberkow/dev/Platform/frontend/src/translations/hu.json, locale='hu', namespace='null'}

JsonNull
	at de.marhali.easyi18n.io.IOHandler.read(IOHandler.java:69)
	at de.marhali.easyi18n.DataStore.lambda$loadFromPersistenceLayer$0(DataStore.java:57)
	at com.intellij.openapi.application.impl.ApplicationImpl.runReadAction(ApplicationImpl.java:839)
	at de.marhali.easyi18n.DataStore.loadFromPersistenceLayer(DataStore.java:55)
	at de.marhali.easyi18n.InstanceManager.lambda$new$1(InstanceManager.java:41)
	at com.intellij.openapi.application.TransactionGuardImpl.runWithWritingAllowed(TransactionGuardImpl.java:214)
	at com.intellij.openapi.application.TransactionGuardImpl.access$200(TransactionGuardImpl.java:21)
	at com.intellij.openapi.application.TransactionGuardImpl$2.run(TransactionGuardImpl.java:196)
	at com.intellij.openapi.application.impl.ApplicationImpl.runIntendedWriteActionOnCurrentThread(ApplicationImpl.java:805)
	at com.intellij.openapi.application.impl.ApplicationImpl.lambda$invokeLater$4(ApplicationImpl.java:348)
	at com.intellij.openapi.application.impl.FlushQueue.doRun(FlushQueue.java:82)
	at com.intellij.openapi.application.impl.FlushQueue.runNextEvent(FlushQueue.java:131)
	at com.intellij.openapi.application.impl.FlushQueue.flushNow(FlushQueue.java:47)
	at com.intellij.openapi.application.impl.FlushQueue$FlushNow.run(FlushQueue.java:187)
	at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:313)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:776)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:727)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
	at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:746)
	at com.intellij.ide.IdeEventQueue.defaultDispatchEvent(IdeEventQueue.java:891)
	at com.intellij.ide.IdeEventQueue._dispatchEvent(IdeEventQueue.java:760)
	at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$6(IdeEventQueue.java:447)
	at com.intellij.openapi.progress.impl.CoreProgressManager.computePrioritized(CoreProgressManager.java:818)
	at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$7(IdeEventQueue.java:446)
	at com.intellij.openapi.application.impl.ApplicationImpl.runIntendedWriteActionOnCurrentThread(ApplicationImpl.java:805)
	at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.java:492)
	at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
	at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
Caused by: java.lang.UnsupportedOperationException: JsonNull
	at com.google.gson.JsonElement.getAsString(JsonElement.java:179)
	at de.marhali.easyi18n.io.parser.json.JsonMapper.read(JsonMapper.java:37)
	at de.marhali.easyi18n.io.parser.json.JsonMapper.read(JsonMapper.java:31)
	at de.marhali.easyi18n.io.parser.json.JsonParserStrategy.read(JsonParserStrategy.java:40)
	at de.marhali.easyi18n.io.IOHandler.read(IOHandler.java:67)
	... 33 more

IDE Error Report

Additional information

null

Exception trace

An error occurred while processing translation files.
Config: SINGLE => JSON (.)
Path: /Users/kyluk/Desktop/checkout-web/src/translations
Please check examples at https://github.com/marhali/easy-i18n before reporting an issue!

java.lang.IllegalArgumentException: Specified locales path is invalid (/Users/kyluk/Desktop/checkout-web/src/translations)
	at de.marhali.easyi18n.io.IOHandler.read(IOHandler.java:59)
	at de.marhali.easyi18n.DataStore.lambda$loadFromPersistenceLayer$0(DataStore.java:57)
	at com.intellij.openapi.application.impl.ApplicationImpl.runReadAction(ApplicationImpl.java:839)
	at de.marhali.easyi18n.DataStore.loadFromPersistenceLayer(DataStore.java:55)
	at de.marhali.easyi18n.service.FileChangeListener$1.lambda$afterVfsChange$1(FileChangeListener.java:58)
	at com.intellij.util.SmartList.forEach(SmartList.java:341)
	at java.base/java.util.Collections$UnmodifiableCollection.forEach(Collections.java:1085)
	at de.marhali.easyi18n.service.FileChangeListener$1.afterVfsChange(FileChangeListener.java:54)
	at com.intellij.openapi.vfs.newvfs.AsyncEventSupport.afterVfsChange(AsyncEventSupport.java:133)
	at com.intellij.openapi.vfs.newvfs.AsyncEventSupport.processEventsFromRefresh(AsyncEventSupport.java:156)
	at com.intellij.openapi.vfs.newvfs.RefreshSessionImpl.fireEventsInWriteAction(RefreshSessionImpl.java:226)
	at com.intellij.openapi.vfs.newvfs.RefreshSessionImpl.lambda$fireEvents$1(RefreshSessionImpl.java:205)
	at com.intellij.openapi.application.impl.ApplicationImpl.lambda$runEdtProgressWriteAction$11(ApplicationImpl.java:911)
	at com.intellij.openapi.progress.impl.CoreProgressManager.lambda$runProcess$2(CoreProgressManager.java:188)
	at com.intellij.openapi.progress.impl.CoreProgressManager.lambda$executeProcessUnderProgress$12(CoreProgressManager.java:624)
	at com.intellij.openapi.progress.impl.CoreProgressManager.registerIndicatorAndRun(CoreProgressManager.java:698)
	at com.intellij.openapi.progress.impl.CoreProgressManager.computeUnderProgress(CoreProgressManager.java:646)
	at com.intellij.openapi.progress.impl.CoreProgressManager.executeProcessUnderProgress(CoreProgressManager.java:623)
	at com.intellij.openapi.progress.impl.ProgressManagerImpl.executeProcessUnderProgress(ProgressManagerImpl.java:66)
	at com.intellij.openapi.progress.impl.CoreProgressManager.runProcess(CoreProgressManager.java:175)
	at com.intellij.openapi.progress.util.PotemkinProgress.runInSwingThread(PotemkinProgress.java:164)
	at com.intellij.openapi.application.impl.ApplicationImpl.lambda$runEdtProgressWriteAction$12(ApplicationImpl.java:911)
	at com.intellij.openapi.application.impl.ApplicationImpl.runWriteActionWithClass(ApplicationImpl.java:935)
	at com.intellij.openapi.application.impl.ApplicationImpl.runEdtProgressWriteAction(ApplicationImpl.java:909)
	at com.intellij.openapi.application.impl.ApplicationImpl.runWriteActionWithNonCancellableProgressInDispatchThread(ApplicationImpl.java:890)
	at com.intellij.openapi.vfs.newvfs.RefreshSessionImpl.lambda$fireEvents$2(RefreshSessionImpl.java:199)
	at com.intellij.openapi.application.WriteAction.lambda$run$1(WriteAction.java:86)
	at com.intellij.openapi.application.impl.ApplicationImpl.runWriteActionWithClass(ApplicationImpl.java:935)
	at com.intellij.openapi.application.impl.ApplicationImpl.runWriteAction(ApplicationImpl.java:961)
	at com.intellij.openapi.application.WriteAction.run(WriteAction.java:85)
	at com.intellij.openapi.vfs.newvfs.RefreshSessionImpl.fireEvents(RefreshSessionImpl.java:198)
	at com.intellij.openapi.vfs.newvfs.RefreshQueueImpl.lambda$runAsyncListeners$9(RefreshQueueImpl.java:148)
	at com.intellij.openapi.application.impl.NonBlockingReadActionImpl$Submission.lambda$safeTransferToEdt$6(NonBlockingReadActionImpl.java:577)
	at com.intellij.openapi.application.TransactionGuardImpl.runWithWritingAllowed(TransactionGuardImpl.java:214)
	at com.intellij.openapi.application.TransactionGuardImpl.access$200(TransactionGuardImpl.java:21)
	at com.intellij.openapi.application.TransactionGuardImpl$2.run(TransactionGuardImpl.java:196)
	at com.intellij.openapi.application.impl.ApplicationImpl.runIntendedWriteActionOnCurrentThread(ApplicationImpl.java:805)
	at com.intellij.openapi.application.impl.ApplicationImpl.lambda$invokeLater$4(ApplicationImpl.java:348)
	at com.intellij.openapi.application.impl.FlushQueue.doRun(FlushQueue.java:82)
	at com.intellij.openapi.application.impl.FlushQueue.runNextEvent(FlushQueue.java:131)
	at com.intellij.openapi.application.impl.FlushQueue.flushNow(FlushQueue.java:47)
	at com.intellij.openapi.application.impl.FlushQueue$FlushNow.run(FlushQueue.java:187)
	at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:313)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:776)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:727)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
	at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:746)
	at com.intellij.ide.IdeEventQueue.defaultDispatchEvent(IdeEventQueue.java:891)
	at com.intellij.ide.IdeEventQueue._dispatchEvent(IdeEventQueue.java:760)
	at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$6(IdeEventQueue.java:447)
	at com.intellij.openapi.progress.impl.CoreProgressManager.computePrioritized(CoreProgressManager.java:818)
	at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$7(IdeEventQueue.java:446)
	at com.intellij.openapi.application.impl.ApplicationImpl.runIntendedWriteActionOnCurrentThread(ApplicationImpl.java:805)
	at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.java:492)
	at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
	at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)

Yaml support

Nice plugin, one of the best.
How about Yaml files support? It's basically superset of Json, but I see yaml localizations quite often

Feature Request: Allow filtering on missing translations

Translation files can get pretty large which impacts their browsability. The plugin can already detect when translations are present in the one language, but absent in the other.

A filter option could be useful here. If we can hide all translations that exist in all languages (perhaps optionally ignoring a language) it would be easier to get an overview on what translations still need some work.

Unity *.meta files recognized as *.properties files

This plugin seems nice and I want to use it to translate a Unity3D project because I use properties files in my Unity3D project.

However, it seems that the *.meta files that Unity creates for every "normal" file are also considered as properties file by this plugin.

Example: I have message.properties and messages_de.properties. Unity creates for these message.properties.meta and messages_de.properties.meta to store some additional information.
Now, the Easy-i18n plugin displays all 4 files in the "Table view". Instead, it should ignore the *.meta files.

IDE Error Report

Additional information

null

Exception trace

An error occurred while processing translation files.
Config: SINGLE => JSON (.)
Path: /Users/kyluk/Desktop/checkout-web/src/translations
Please check examples at https://github.com/marhali/easy-i18n before reporting an issue!

java.lang.IllegalArgumentException: Specified locales path is invalid (/Users/kyluk/Desktop/checkout-web/src/translations)
	at de.marhali.easyi18n.io.IOHandler.read(IOHandler.java:59)
	at de.marhali.easyi18n.DataStore.lambda$loadFromPersistenceLayer$0(DataStore.java:57)
	at com.intellij.openapi.application.impl.ApplicationImpl.runReadAction(ApplicationImpl.java:839)
	at de.marhali.easyi18n.DataStore.loadFromPersistenceLayer(DataStore.java:55)
	at de.marhali.easyi18n.InstanceManager.lambda$new$1(InstanceManager.java:41)
	at com.intellij.openapi.application.TransactionGuardImpl.runWithWritingAllowed(TransactionGuardImpl.java:214)
	at com.intellij.openapi.application.TransactionGuardImpl.access$200(TransactionGuardImpl.java:21)
	at com.intellij.openapi.application.TransactionGuardImpl$2.run(TransactionGuardImpl.java:196)
	at com.intellij.openapi.application.impl.ApplicationImpl.runIntendedWriteActionOnCurrentThread(ApplicationImpl.java:805)
	at com.intellij.openapi.application.impl.ApplicationImpl.lambda$invokeLater$4(ApplicationImpl.java:348)
	at com.intellij.openapi.application.impl.FlushQueue.doRun(FlushQueue.java:82)
	at com.intellij.openapi.application.impl.FlushQueue.runNextEvent(FlushQueue.java:131)
	at com.intellij.openapi.application.impl.FlushQueue.flushNow(FlushQueue.java:47)
	at com.intellij.openapi.application.impl.FlushQueue$FlushNow.run(FlushQueue.java:187)
	at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:313)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:776)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:727)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
	at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:746)
	at com.intellij.ide.IdeEventQueue.defaultDispatchEvent(IdeEventQueue.java:891)
	at com.intellij.ide.IdeEventQueue._dispatchEvent(IdeEventQueue.java:760)
	at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$6(IdeEventQueue.java:447)
	at com.intellij.openapi.progress.impl.CoreProgressManager.computePrioritized(CoreProgressManager.java:818)
	at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$7(IdeEventQueue.java:446)
	at com.intellij.openapi.application.impl.ApplicationImpl.runIntendedWriteActionOnCurrentThread(ApplicationImpl.java:805)
	at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.java:492)
	at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
	at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)

Improve search method

Hi, I'm using this plug-in in PhpStorm IDE and it's really nice but the search method could be improved.
For example, I have those keys :

  • TEST
    • A => example a
    • B => example b
    • C => example c

I would like to type "exam" and all key must be return. Or "tes" and do the same. The searching could be by key or content and not exactly the correct word. And case insensitive :)

Could you think it's possible to update it ?

Thanks in advance.

npe: I18nCompletionProvider

  • also check NPE's for unconfigured projects
  • exception:
    java.lang.NullPointerException at de.marhali.easyi18n.ui.editor.I18nCompletionProvider.addCompletions(I18nCompletionProvider.java:40) at com.intellij.codeInsight.completion.CompletionProvider.addCompletionVariants(CompletionProvider.java:34) at com.intellij.codeInsight.completion.CompletionContributor.fillCompletionVariants(CompletionContributor.java:156) at com.intellij.codeInsight.completion.CompletionService.getVariantsFromContributors(CompletionService.java:77) at com.intellij.codeInsight.completion.CompletionResultSet.runRemainingContributors(CompletionResultSet.java:154) at com.intellij.codeInsight.completion.CompletionResultSet.runRemainingContributors(CompletionResultSet.java:146) at com.intellij.codeInsight.completion.CompletionResultSet.runRemainingContributors(CompletionResultSet.java:142) at com.intellij.codeInsight.completion.CompletionResultSet.runRemainingContributors(CompletionResultSet.java:132) at com.intellij.codeInsight.completion.XmlNoVariantsDelegator.fillCompletionVariants(XmlNoVariantsDelegator.java:12) at com.intellij.codeInsight.completion.CompletionService.getVariantsFromContributors(CompletionService.java:77) at com.intellij.codeInsight.completion.CompletionResultSet.runRemainingContributors(CompletionResultSet.java:154) at com.intellij.codeInsight.completion.CompletionResultSet.runRemainingContributors(CompletionResultSet.java:146) at com.intellij.codeInsight.completion.CompletionResultSet.runRemainingContributors(CompletionResultSet.java:142) at com.intellij.codeInsight.completion.XmlCompletionContributor$3.addCompletions(XmlCompletionContributor.java:127) at com.intellij.codeInsight.completion.CompletionProvider.addCompletionVariants(CompletionProvider.java:34) at com.intellij.codeInsight.completion.CompletionContributor.fillCompletionVariants(CompletionContributor.java:156) at com.intellij.codeInsight.completion.XmlCompletionContributor.fillCompletionVariants(XmlCompletionContributor.java:182) at com.intellij.codeInsight.completion.CompletionService.getVariantsFromContributors(CompletionService.java:77) at com.intellij.codeInsight.completion.CompletionResultSet.runRemainingContributors(CompletionResultSet.java:154) at com.intellij.codeInsight.completion.CompletionResultSet.runRemainingContributors(CompletionResultSet.java:146) at com.intellij.codeInsight.completion.CompletionResultSet.runRemainingContributors(CompletionResultSet.java:142) at com.intellij.codeInsight.template.impl.LiveTemplateCompletionContributor$1.addCompletions(LiveTemplateCompletionContributor.java:89) at com.intellij.codeInsight.completion.CompletionProvider.addCompletionVariants(CompletionProvider.java:34) at com.intellij.codeInsight.completion.CompletionContributor.fillCompletionVariants(CompletionContributor.java:156) at com.intellij.codeInsight.completion.CompletionService.getVariantsFromContributors(CompletionService.java:77) at com.intellij.codeInsight.completion.CompletionService.getVariantsFromContributors(CompletionService.java:60) at com.intellij.codeInsight.completion.CompletionService.performCompletion(CompletionService.java:133) at com.intellij.codeInsight.completion.BaseCompletionService.performCompletion(BaseCompletionService.java:41) at com.intellij.codeInsight.completion.CompletionProgressIndicator.lambda$calculateItems$12(CompletionProgressIndicator.java:863) at com.intellij.util.indexing.FileBasedIndex.lambda$ignoreDumbMode$0(FileBasedIndex.java:163) at com.intellij.openapi.util.RecursionManager$1.computePreventingRecursion(RecursionManager.java:111) at com.intellij.util.indexing.FileBasedIndexEx.ignoreDumbMode(FileBasedIndexEx.java:574) at com.intellij.util.indexing.FileBasedIndex.ignoreDumbMode(FileBasedIndex.java:162) at com.intellij.util.indexing.DumbModeAccessType.ignoreDumbMode(DumbModeAccessType.java:43) at com.intellij.codeInsight.completion.CompletionProgressIndicator.calculateItems(CompletionProgressIndicator.java:859) at com.intellij.codeInsight.completion.CompletionProgressIndicator.runContributors(CompletionProgressIndicator.java:847) at com.intellij.codeInsight.completion.CodeCompletionHandlerBase.lambda$startContributorThread$6(CodeCompletionHandlerBase.java:353) at com.intellij.codeInsight.completion.AsyncCompletion.lambda$tryReadOrCancel$5(CompletionThreading.java:172) at com.intellij.openapi.application.impl.ApplicationImpl.tryRunReadAction(ApplicationImpl.java:1096) at com.intellij.codeInsight.completion.AsyncCompletion.tryReadOrCancel(CompletionThreading.java:170) at com.intellij.codeInsight.completion.CodeCompletionHandlerBase.lambda$startContributorThread$7(CodeCompletionHandlerBase.java:345) at com.intellij.codeInsight.completion.AsyncCompletion.lambda$startThread$0(CompletionThreading.java:95) at com.intellij.openapi.progress.impl.CoreProgressManager.lambda$runProcess$2(CoreProgressManager.java:178) at com.intellij.openapi.progress.impl.CoreProgressManager.registerIndicatorAndRun(CoreProgressManager.java:688) at com.intellij.openapi.progress.impl.CoreProgressManager.executeProcessUnderProgress(CoreProgressManager.java:634) at com.intellij.openapi.progress.impl.ProgressManagerImpl.executeProcessUnderProgress(ProgressManagerImpl.java:64) at com.intellij.openapi.progress.impl.CoreProgressManager.runProcess(CoreProgressManager.java:165) at com.intellij.codeInsight.completion.AsyncCompletion.lambda$startThread$1(CompletionThreading.java:91) at com.intellij.util.RunnableCallable.call(RunnableCallable.java:20) at com.intellij.util.RunnableCallable.call(RunnableCallable.java:11) at com.intellij.openapi.application.impl.ApplicationImpl$1.call(ApplicationImpl.java:265) at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) at java.base/java.util.concurrent.Executors$PrivilegedThreadFactory$1$1.run(Executors.java:668) at java.base/java.util.concurrent.Executors$PrivilegedThreadFactory$1$1.run(Executors.java:665) at java.base/java.security.AccessController.doPrivileged(Native Method) at java.base/java.util.concurrent.Executors$PrivilegedThreadFactory$1.run(Executors.java:665) at java.base/java.lang.Thread.run(Thread.java:834)

IDE fatal Error

Hi.

With last version of Webstorm and Easy i18n (1.6.0) after anything in code, IDE show error.
Please fixit.After this fail, Webstorm refuses to suggest code. Not especialy with Easy i18n, but everywhere.

java.lang.NullPointerException
at de.marhali.easyi18n.editor.KeyCompletionProvider.addCompletions(KeyCompletionProvider.java:80)
at com.intellij.codeInsight.completion.CompletionProvider.addCompletionVariants(CompletionProvider.java:25)
at com.intellij.codeInsight.completion.CompletionContributor.fillCompletionVariants(CompletionContributor.java:158)
at com.intellij.codeInsight.completion.CompletionService.getVariantsFromContributors(CompletionService.java:77)
at com.intellij.codeInsight.completion.CompletionResultSet.runRemainingContributors(CompletionResultSet.java:154)
at com.intellij.codeInsight.completion.CompletionResultSet.runRemainingContributors(CompletionResultSet.java:146)
at com.intellij.codeInsight.completion.CompletionResultSet.runRemainingContributors(CompletionResultSet.java:142)
at com.intellij.codeInsight.template.impl.LiveTemplateCompletionContributor$1.addCompletions(LiveTemplateCompletionContributor.java:89)
at com.intellij.codeInsight.completion.CompletionProvider.addCompletionVariants(CompletionProvider.java:25)
at com.intellij.codeInsight.completion.CompletionContributor.fillCompletionVariants(CompletionContributor.java:158)
at com.intellij.codeInsight.completion.CompletionService.getVariantsFromContributors(CompletionService.java:77)
at com.intellij.codeInsight.completion.CompletionService.getVariantsFromContributors(CompletionService.java:60)
at com.intellij.codeInsight.completion.CompletionService.performCompletion(CompletionService.java:133)
at com.intellij.codeInsight.completion.BaseCompletionService.performCompletion(BaseCompletionService.java:41)
at com.intellij.codeInsight.completion.CompletionProgressIndicator.lambda$calculateItems$12(CompletionProgressIndicator.java:865)
at com.intellij.util.indexing.FileBasedIndex.lambda$ignoreDumbMode$0(FileBasedIndex.java:164)
at com.intellij.openapi.util.RecursionManager$1.computePreventingRecursion(RecursionManager.java:114)
at com.intellij.util.indexing.FileBasedIndexEx.ignoreDumbMode(FileBasedIndexEx.java:581)
at com.intellij.util.indexing.FileBasedIndex.ignoreDumbMode(FileBasedIndex.java:163)
at com.intellij.util.indexing.DumbModeAccessType.ignoreDumbMode(DumbModeAccessType.java:43)
at com.intellij.codeInsight.completion.CompletionProgressIndicator.calculateItems(CompletionProgressIndicator.java:861)
at com.intellij.codeInsight.completion.CompletionProgressIndicator.runContributors(CompletionProgressIndicator.java:849)
at com.intellij.codeInsight.completion.CodeCompletionHandlerBase.lambda$startContributorThread$6(CodeCompletionHandlerBase.java:352)
at com.intellij.codeInsight.completion.AsyncCompletion.lambda$tryReadOrCancel$5(CompletionThreading.java:172)
at com.intellij.openapi.application.impl.ApplicationImpl.tryRunReadAction(ApplicationImpl.java:1084)
at com.intellij.codeInsight.completion.AsyncCompletion.tryReadOrCancel(CompletionThreading.java:170)
at com.intellij.codeInsight.completion.CodeCompletionHandlerBase.lambda$startContributorThread$7(CodeCompletionHandlerBase.java:344)
at com.intellij.codeInsight.completion.AsyncCompletion.lambda$startThread$0(CompletionThreading.java:95)
at com.intellij.openapi.progress.impl.CoreProgressManager.lambda$runProcess$2(CoreProgressManager.java:188)
at com.intellij.openapi.progress.impl.CoreProgressManager.lambda$executeProcessUnderProgress$12(CoreProgressManager.java:624)
at com.intellij.openapi.progress.impl.CoreProgressManager.registerIndicatorAndRun(CoreProgressManager.java:698)
at com.intellij.openapi.progress.impl.CoreProgressManager.computeUnderProgress(CoreProgressManager.java:646)
at com.intellij.openapi.progress.impl.CoreProgressManager.executeProcessUnderProgress(CoreProgressManager.java:623)
at com.intellij.openapi.progress.impl.ProgressManagerImpl.executeProcessUnderProgress(ProgressManagerImpl.java:66)
at com.intellij.openapi.progress.impl.CoreProgressManager.runProcess(CoreProgressManager.java:175)
at com.intellij.codeInsight.completion.AsyncCompletion.lambda$startThread$1(CompletionThreading.java:91)
at com.intellij.openapi.application.impl.ApplicationImpl$1.run(ApplicationImpl.java:263)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.util.concurrent.Executors$PrivilegedThreadFactory$1$1.run(Executors.java:668)
at java.base/java.util.concurrent.Executors$PrivilegedThreadFactory$1$1.run(Executors.java:665)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.base/java.util.concurrent.Executors$PrivilegedThreadFactory$1.run(Executors.java:665)
at java.base/java.lang.Thread.run(Thread.java:829)

Not working on namespaced files

There is my files tree.

image

I tryed many configs but nothing working, the plugin cannot find my files.

Can somebody help? What is the needed config?

Pretty sure I did nothing bad.

Thanks.

Improve DataBus: Unify Filter Listener

Search query filter and missing values filter does not work well together. We can unify these listeners to a single listener which will take care of UI manipulation.

Optional: Outsource UI manipulation into a single component which will supervise both tool-window views.

Filter Actions to take care of

  • toggle missing translations
  • toggle duplicated translation values
  • search by query

Additional data bus related events

  • update translation data
  • focus translation key

Conclusion => We should redesign how the event bus works. All the previous events must work together and a single state should not override other states.

Implementation

Abstract

Implement a new StateMachine which takes care of applying the correct update series to display a consistent UI.
The state machine caches the current filters to apply them on data changes or other changes.

  • first: update data (full list, not filtered)
  • middle: apply all filters
  • last: focus key (focus key after applying all filters)

Solution with current features

  1. update data
  2. toggle missing translations
  3. toggle duplicated translation values
  4. search by query
  5. focus key

For our ui tabs we want to use a single underlying component to apply all filters and handle event updates.
Maybe we can move the cache into this component.

FilterComponent

  • onUpdateData(filtered TranslationData)
  • focusKey(KeyPath)
  • expandAll()

Unexpected character escaping and sorting

I have a properties (encoded in UTF-8) file like

# test_comment1=this is the first comment
! test_comment2=this is the second comment
test_helloWorld=Hello world!
test_equals=before=after
test_parameters=First name: {firstName}, second name: {secondName}
test_nonAscii=üäößêéèáà
test_quotes="All these outer and 'single quotes' and "double quotes" are kept"
test_spaceAtTheEndNotAroundEquals  =  Space around the equals sign is trimmed, but the ending space is kept: 
test_tab=Before tab\tafter tab
test_newline=First line\nAfter newline\rAfter carriage return
test_KeepSpace=\ <- white-space -> 
test_targetCities=\
        Detroit,\
        Chicago,\
        Los Angeles
test_backslash=\\Just two backslashes\\

When I use Easy-i18n, then

  • The lines are reordered
    • I can't say how they are ordered. It is not alphabetically.
  • Some characters are escaped.
    • for example, : becomes : and ! becomes ! and = becomes =
  • Everything changes, even when I only change a single translation

I did not expect this.

  • Unneeded escaping of characters should not happen.
  • Reordering translations would be nice as an optional feature. The order should then be alphabetically (or maybe configurable).
  • Lines where the translation has not been changed should stay the same.
    • To implement this, the lines of the original file could be stored in order. This data structure is updated on translation change. On Save, this data structure is flushed back to the file.
    • Note that this is relevant for version control (to see which translations have been changed).

IntelliJ 2022 Support?

Will IntelliJ 2022 be supported at some point?
2022.1 is now in Beta State and thus more people are transitioning, just to find out that this amazing plugin unfortunately doesn't work there.
error message

Keyboard shortcut seems not working

When I type cmd-n for creating a translation, it shows an empty menu and doesn't do what the + button does. Is it by design?
I think it'd be great to have keyboard shortcuts for managing entries.

[Feature Requests] Configuration Options and Support for plurals and context

Hello
I'm trying out some i18n plugins for IntelliJ in combination with i18next(-react), and I found yours and it's one of the better.

In i18next the default namespace separator is : or the ns-attribute in the parameter object.
e.g. t('common:submit') resp. t('submit', { ns: 'common' })

Therefore I'm missing some, in my opinion, useful (configuration) features:

  • The namespace, key, plurals and context separators should be customizable.
  • an option to define a default namespace, which then is not given in the key e.g. t('submit') where common is now the default ns.

It would also be great when you add support for plurals and context

Plurals, Context and both combined

{
  "keyWithCount_one": "{{count}} item",
  "keyWithCount_other": "{{count}} items"

  "friend": "A friend",
  "friend_male": "A boyfriend",
  "friend_female": "A girlfriend"

  "friend_male_one": "A boyfriend",
  "friend_female_one": "A girlfriend",
  "friend_male_other": "{{count}} boyfriends",
  "friend_female_other": "{{count}} girlfriends"
}
i18next.t('keyWithCount', {count: 0}); // -> "0 items"
i18next.t('keyWithCount', {count: 1}); // -> "1 item"
i18next.t('keyWithCount', {count: 5}); // -> "5 items"

i18next.t('friend'); // -> "A friend"
i18next.t('friend', {context: 'male' }); // -> "A boyfriend"
i18next.t('friend', {context: 'female' }); // -> "A girlfriend"

i18next.t('friend', {context: 'male', count: 1}); // -> "A boyfriend"
i18next.t('friend', {context: 'female', count: 1}); // -> "A girlfriend"
i18next.t('friend', {context: 'male', count: 100}); // -> "100 boyfriends"
i18next.t('friend', {context: 'female', count: 100}); // -> "100 girlfriends"

So if there is a count, context or both of them in the parameter object if would be great to see all matching keys in the hover.
Be aware of, that there are languages with at least 5 plurals besides the singular.

Kind Regards
Frank

IDE Error Report

Additional information

null

Exception trace

An error occurred while processing translation files.
Config: SINGLE => JSON (.)
Path: null
Please check examples at https://github.com/marhali/easy-i18n before reporting an issue!

java.lang.IllegalArgumentException: Locales path must not be empty
	at de.marhali.easyi18n.io.IOHandler.read(IOHandler.java:52)
	at de.marhali.easyi18n.DataStore.lambda$loadFromPersistenceLayer$0(DataStore.java:56)
	at com.intellij.openapi.application.impl.ApplicationImpl.runReadAction(ApplicationImpl.java:839)
	at de.marhali.easyi18n.DataStore.loadFromPersistenceLayer(DataStore.java:54)
	at de.marhali.easyi18n.InstanceManager.lambda$new$1(InstanceManager.java:41)
	at com.intellij.openapi.application.TransactionGuardImpl.runWithWritingAllowed(TransactionGuardImpl.java:214)
	at com.intellij.openapi.application.TransactionGuardImpl.access$200(TransactionGuardImpl.java:21)
	at com.intellij.openapi.application.TransactionGuardImpl$2.run(TransactionGuardImpl.java:196)
	at com.intellij.openapi.application.impl.ApplicationImpl.runIntendedWriteActionOnCurrentThread(ApplicationImpl.java:805)
	at com.intellij.openapi.application.impl.ApplicationImpl.lambda$invokeLater$4(ApplicationImpl.java:348)
	at com.intellij.openapi.application.impl.FlushQueue.doRun(FlushQueue.java:82)
	at com.intellij.openapi.application.impl.FlushQueue.runNextEvent(FlushQueue.java:131)
	at com.intellij.openapi.application.impl.FlushQueue.flushNow(FlushQueue.java:47)
	at com.intellij.openapi.application.impl.FlushQueue$FlushNow.run(FlushQueue.java:187)
	at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:313)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:776)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:727)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
	at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:746)
	at com.intellij.ide.IdeEventQueue.defaultDispatchEvent(IdeEventQueue.java:891)
	at com.intellij.ide.IdeEventQueue._dispatchEvent(IdeEventQueue.java:760)
	at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$6(IdeEventQueue.java:447)
	at com.intellij.openapi.progress.impl.CoreProgressManager.computePrioritized(CoreProgressManager.java:818)
	at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$7(IdeEventQueue.java:446)
	at com.intellij.openapi.application.impl.ApplicationImpl.runIntendedWriteActionOnCurrentThread(ApplicationImpl.java:805)
	at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.java:492)
	at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
	at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)

IDE Error Report

Additional information

null

Exception trace

null

java.lang.IndexOutOfBoundsException: Index 196 out of bounds for length 0
	at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:64)
	at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:70)
	at java.base/jdk.internal.util.Preconditions.checkIndex(Preconditions.java:248)
	at java.base/java.util.Objects.checkIndex(Objects.java:372)
	at java.base/java.util.ArrayList.get(ArrayList.java:459)
	at de.marhali.easyi18n.tabs.mapper.TableModelMapper.getValueAt(TableModelMapper.java:117)
	at java.desktop/javax.swing.JTable.getValueAt(JTable.java:2706)
	at de.marhali.easyi18n.action.AddAction.detectPreKey(AddAction.java:60)
	at de.marhali.easyi18n.action.AddAction.actionPerformed(AddAction.java:35)
	at com.intellij.openapi.actionSystem.impl.ActionButton.actionPerformed(ActionButton.java:178)
	at com.intellij.openapi.actionSystem.impl.ActionButton.lambda$performAction$0(ActionButton.java:154)
	at com.intellij.openapi.actionSystem.ex.ActionUtil.performDumbAwareWithCallbacks(ActionUtil.java:260)
	at com.intellij.openapi.actionSystem.impl.ActionButton.performAction(ActionButton.java:154)
	at com.intellij.openapi.actionSystem.impl.ActionButton.processMouseEvent(ActionButton.java:449)
	at java.desktop/java.awt.Component.processEvent(Component.java:6419)
	at java.desktop/java.awt.Container.processEvent(Container.java:2263)
	at java.desktop/java.awt.Component.dispatchEventImpl(Component.java:5029)
	at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2321)
	at java.desktop/java.awt.Component.dispatchEvent(Component.java:4861)
	at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4918)
	at java.desktop/java.awt.LightweightDispatcher.processMouseEvent(Container.java:4547)
	at java.desktop/java.awt.LightweightDispatcher.dispatchEvent(Container.java:4488)
	at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2307)
	at java.desktop/java.awt.Window.dispatchEventImpl(Window.java:2790)
	at java.desktop/java.awt.Component.dispatchEvent(Component.java:4861)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:778)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:727)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:95)
	at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:751)
	at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:749)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
	at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:748)
	at com.intellij.ide.IdeEventQueue.defaultDispatchEvent(IdeEventQueue.java:891)
	at com.intellij.ide.IdeEventQueue.dispatchMouseEvent(IdeEventQueue.java:820)
	at com.intellij.ide.IdeEventQueue._dispatchEvent(IdeEventQueue.java:757)
	at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$6(IdeEventQueue.java:447)
	at com.intellij.openapi.progress.impl.CoreProgressManager.computePrioritized(CoreProgressManager.java:818)
	at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$7(IdeEventQueue.java:446)
	at com.intellij.openapi.application.impl.ApplicationImpl.runIntendedWriteActionOnCurrentThread(ApplicationImpl.java:805)
	at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.java:498)
	at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
	at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)

IDE Error Report

Additional information

null

Exception trace

An error occurred while processing translation files.
Config: SINGLE => JSON (.)
Path: null
Please check examples at https://github.com/marhali/easy-i18n before reporting an issue!

java.lang.IllegalArgumentException: Locales path must not be empty
	at de.marhali.easyi18n.io.IOHandler.read(IOHandler.java:52)
	at de.marhali.easyi18n.DataStore.lambda$loadFromPersistenceLayer$0(DataStore.java:56)
	at com.intellij.openapi.application.impl.ApplicationImpl.runReadAction(ApplicationImpl.java:839)
	at de.marhali.easyi18n.DataStore.loadFromPersistenceLayer(DataStore.java:54)
	at de.marhali.easyi18n.InstanceManager.lambda$new$1(InstanceManager.java:41)
	at com.intellij.openapi.application.TransactionGuardImpl.runWithWritingAllowed(TransactionGuardImpl.java:214)
	at com.intellij.openapi.application.TransactionGuardImpl.access$200(TransactionGuardImpl.java:21)
	at com.intellij.openapi.application.TransactionGuardImpl$2.run(TransactionGuardImpl.java:196)
	at com.intellij.openapi.application.impl.ApplicationImpl.runIntendedWriteActionOnCurrentThread(ApplicationImpl.java:805)
	at com.intellij.openapi.application.impl.ApplicationImpl.lambda$invokeLater$4(ApplicationImpl.java:348)
	at com.intellij.openapi.application.impl.FlushQueue.doRun(FlushQueue.java:82)
	at com.intellij.openapi.application.impl.FlushQueue.runNextEvent(FlushQueue.java:131)
	at com.intellij.openapi.application.impl.FlushQueue.flushNow(FlushQueue.java:47)
	at com.intellij.openapi.application.impl.FlushQueue$FlushNow.run(FlushQueue.java:187)
	at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:313)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:776)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:727)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
	at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:746)
	at com.intellij.ide.IdeEventQueue.defaultDispatchEvent(IdeEventQueue.java:891)
	at com.intellij.ide.IdeEventQueue._dispatchEvent(IdeEventQueue.java:760)
	at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$6(IdeEventQueue.java:447)
	at com.intellij.openapi.progress.impl.CoreProgressManager.computePrioritized(CoreProgressManager.java:818)
	at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$7(IdeEventQueue.java:446)
	at com.intellij.openapi.application.impl.ApplicationImpl.runIntendedWriteActionOnCurrentThread(ApplicationImpl.java:805)
	at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.java:492)
	at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
	at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)

Broken folding for vue files

Version 1.7.0 totally broke code folding in vue files.
Left bar folding icons disappeared. Hotkeys not working.

Optimize exception handling on IO ops

If the translation folder contains files that are not relevant, exceptions occur with EasyI18n.
For the user itself it is then not directly obvious why the error occurred.

The text in the exception should be more detailed and present suggested solutions (=> Translation File Pattern).

Support for translation preview in template

Hi @marhali

I have a Vue app, and while the option for showing a preview of the key value on hover already exists, I would love if you could provide another option (possibly disabled by default) that would preview the key value inside the Vue template (by default, without the need of hovering), and the key would only be shown while clicking on the key.

This feature is enabled by default by the alternative extension I18n Ally on VScode (although they do not currently support that feature on webstorm)
image
See the translations (default english) values in our templates directly would I believe, significantly increase the readability/interpretability of our components (vs abstract key names)
BTW I really like your extension, great work!

IDE Error Report

Additional information

null

Exception trace

null

java.lang.NullPointerException
	at de.marhali.easyi18n.action.AddAction.detectPreKey(AddAction.java:41)
	at de.marhali.easyi18n.action.AddAction.actionPerformed(AddAction.java:35)
	at com.intellij.openapi.actionSystem.ex.ActionUtil.lambda$performActionDumbAwareWithCallbacks$4(ActionUtil.java:235)
	at com.intellij.openapi.actionSystem.ex.ActionUtil.performDumbAwareWithCallbacks(ActionUtil.java:256)
	at com.intellij.openapi.actionSystem.ex.ActionUtil.performActionDumbAwareWithCallbacks(ActionUtil.java:235)
	at com.intellij.ui.popup.ActionPopupStep.performAction(ActionPopupStep.java:240)
	at com.intellij.ui.popup.ActionPopupStep.performAction(ActionPopupStep.java:249)
	at com.intellij.ui.popup.ActionPopupStep.performAction(ActionPopupStep.java:245)
	at com.intellij.ui.popup.ActionPopupStep.lambda$onChosen$1(ActionPopupStep.java:220)
	at com.intellij.openapi.application.TransactionGuardImpl.performActivity(TransactionGuardImpl.java:106)
	at com.intellij.openapi.application.TransactionGuardImpl.performUserActivity(TransactionGuardImpl.java:95)
	at com.intellij.ui.popup.AbstractPopup.lambda$dispose$18(AbstractPopup.java:1538)
	at com.intellij.util.ui.EdtInvocationManager.invokeLaterIfNeeded(EdtInvocationManager.java:101)
	at com.intellij.ide.IdeEventQueue.ifFocusEventsInTheQueue(IdeEventQueue.java:179)
	at com.intellij.ide.IdeEventQueue.executeWhenAllFocusEventsLeftTheQueue(IdeEventQueue.java:132)
	at com.intellij.openapi.wm.impl.FocusManagerImpl.doWhenFocusSettlesDown(FocusManagerImpl.java:172)
	at com.intellij.ui.popup.AbstractPopup.dispose(AbstractPopup.java:1535)
	at com.intellij.ui.popup.WizardPopup.dispose(WizardPopup.java:162)
	at com.intellij.ui.popup.list.ListPopupImpl.dispose(ListPopupImpl.java:326)
	at com.intellij.ui.popup.PopupFactoryImpl$ActionGroupPopup.dispose(PopupFactoryImpl.java:272)
	at com.intellij.openapi.util.ObjectTree.runWithTrace(ObjectTree.java:139)
	at com.intellij.openapi.util.ObjectTree.executeAll(ObjectTree.java:169)
	at com.intellij.openapi.util.Disposer.dispose(Disposer.java:219)
	at com.intellij.openapi.util.Disposer.dispose(Disposer.java:207)
	at com.intellij.ui.popup.WizardPopup.disposeAllParents(WizardPopup.java:266)
	at com.intellij.ui.popup.list.ListPopupImpl.handleNextStep(ListPopupImpl.java:434)
	at com.intellij.ui.popup.list.ListPopupImpl._handleSelect(ListPopupImpl.java:406)
	at com.intellij.ui.popup.list.ListPopupImpl.handleSelect(ListPopupImpl.java:356)
	at com.intellij.ui.popup.list.ListPopupImpl$1.actionPerformed(ListPopupImpl.java:269)
	at com.intellij.ui.popup.WizardPopup.proceedKeyEvent(WizardPopup.java:378)
	at com.intellij.ui.popup.WizardPopup.dispatch(WizardPopup.java:354)
	at com.intellij.ui.popup.PopupDispatcher.dispatchKeyEvent(PopupDispatcher.java:112)
	at com.intellij.ui.popup.PopupDispatcher.dispatch(PopupDispatcher.java:148)
	at com.intellij.ide.IdePopupManager.dispatch(IdePopupManager.java:109)
	at com.intellij.ide.IdeEventQueue._dispatchEvent(IdeEventQueue.java:710)
	at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$6(IdeEventQueue.java:439)
	at com.intellij.openapi.progress.impl.CoreProgressManager.computePrioritized(CoreProgressManager.java:803)
	at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$7(IdeEventQueue.java:438)
	at com.intellij.openapi.application.TransactionGuardImpl.performActivity(TransactionGuardImpl.java:119)
	at com.intellij.ide.IdeEventQueue.performActivity(IdeEventQueue.java:604)
	at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$8(IdeEventQueue.java:436)
	at com.intellij.openapi.application.impl.ApplicationImpl.runIntendedWriteActionOnCurrentThread(ApplicationImpl.java:873)
	at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.java:484)
	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)

Yaml translations behavior is inconsistent when key contains dots

When a translation key has a dot in the name, the plugin is not able to read the value of that key.
It does recognize the existence of the key, however it will report it as missing for the language.

Example:

Consider the following two translation files:

en.yaml

base:
  firstKey: 'value'
  second.key: 'other value'
  missing.key: 'value missing in nl'

nl.yaml

base:
  firstKey: 'waarde'
  second.key: 'hello'
  second:
    key: 'andere waarde'

easy-i18n interprets this as such:
image
and
image

In addition, trying to edit second: key: ... will show the value of second.key: ...
image

While the dot in the key does technically does not mean anything in the YAML spec, the plugin should be able to handle these cases by either:

  1. Considering the dot as a separator (making second.key: ... and second: key: ... equivalent)
  2. Handling these two cases as separate values

Personally, I feel like the second should be the case as YAML disallows duplicate keys in the same object, but does allow the "same" name when nesting.

Support for react-intl json format

Hi.

In our project we use react-intl library which has messages in json too.
In this case the format of json is

{
 "some.nested.property": "Some nested property",
 "oneLevel": "One level syntax"
}

Now this plugin dont recognize these syntax. Only one level. Can you add to plugin?

Thx

Support arrays

Currently if I try to load a translation file that includes an array (needed for the UI framework localization), the plugin crashes. It'd be nice to handle them, if possibile, BabelEdit does that without any problem. Otherwise it's also okay to not support them in the UI but still load and save translations.

Thanks

IDE Error Report

Additional information

null

Exception trace

null

com.intellij.serviceContainer.AlreadyDisposedException: Cannot create de.marhali.easyi18n.service.SettingsService because container is already disposed (container=Project(name=1win-four, containerState=DISPOSE_COMPLETED, componentStore=/Users/vadimpoluhin/WebstormProjects/1win-four) (disposed))
	at com.intellij.serviceContainer.ContainerUtilKt.throwAlreadyDisposedError(containerUtil.kt:34)
	at com.intellij.serviceContainer.ComponentManagerImpl.doGetService(ComponentManagerImpl.kt:617)
	at com.intellij.serviceContainer.ComponentManagerImpl.getService(ComponentManagerImpl.kt:569)
	at com.intellij.openapi.client.ClientAwareComponentManager.getFromSelfOrCurrentSession(ClientAwareComponentManager.kt:37)
	at com.intellij.openapi.client.ClientAwareComponentManager.getService(ClientAwareComponentManager.kt:22)
	at de.marhali.easyi18n.service.SettingsService.getInstance(SettingsService.java:19)
	at de.marhali.easyi18n.DataStore.loadFromPersistenceLayer(DataStore.java:51)
	at de.marhali.easyi18n.service.FileChangeListener$1.lambda$afterVfsChange$1(FileChangeListener.java:58)
	at java.base/java.lang.Iterable.forEach(Iterable.java:75)
	at de.marhali.easyi18n.service.FileChangeListener$1.afterVfsChange(FileChangeListener.java:54)
	at com.intellij.openapi.vfs.newvfs.AsyncEventSupport.afterVfsChange(AsyncEventSupport.java:133)
	at com.intellij.openapi.vfs.newvfs.AsyncEventSupport$1.after(AsyncEventSupport.java:65)
	at com.intellij.util.messages.impl.MessageBusImpl.invokeMethod(MessageBusImpl.java:645)
	at com.intellij.util.messages.impl.MessageBusImpl.invokeListener(MessageBusImpl.java:620)
	at com.intellij.util.messages.impl.MessageBusImpl.deliverMessage(MessageBusImpl.java:417)
	at com.intellij.util.messages.impl.MessageBusImpl.pumpWaitingBuses(MessageBusImpl.java:390)
	at com.intellij.util.messages.impl.MessageBusImpl.pumpMessages(MessageBusImpl.java:372)
	at com.intellij.util.messages.impl.MessageBusImpl.access$200(MessageBusImpl.java:33)
	at com.intellij.util.messages.impl.MessageBusImpl$MessagePublisher.invoke(MessageBusImpl.java:179)
	at com.sun.proxy.$Proxy104.after(Unknown Source)
	at com.intellij.openapi.vfs.newvfs.persistent.PersistentFSImpl.fireAfterEvents(PersistentFSImpl.java:1188)
	at com.intellij.openapi.vfs.newvfs.persistent.PersistentFSImpl$3.close(PersistentFSImpl.java:780)
	at com.intellij.openapi.fileEditor.impl.LoadTextUtil.write(LoadTextUtil.java:450)
	at com.intellij.openapi.fileEditor.impl.FileDocumentManagerImpl.lambda$doSaveDocumentInWriteAction$4(FileDocumentManagerImpl.java:417)
	at com.intellij.pom.core.impl.PomModelImpl.guardPsiModificationsIn(PomModelImpl.java:326)
	at com.intellij.openapi.fileEditor.impl.FileDocumentManagerImpl.doSaveDocumentInWriteAction(FileDocumentManagerImpl.java:406)
	at com.intellij.openapi.fileEditor.impl.FileDocumentManagerImpl.lambda$doSaveDocument$2(FileDocumentManagerImpl.java:367)
	at com.intellij.openapi.application.WriteAction.lambda$run$1(WriteAction.java:86)
	at com.intellij.openapi.application.impl.ApplicationImpl.runWriteActionWithClass(ApplicationImpl.java:935)
	at com.intellij.openapi.application.impl.ApplicationImpl.runWriteAction(ApplicationImpl.java:961)
	at com.intellij.openapi.application.WriteAction.run(WriteAction.java:85)
	at com.intellij.openapi.fileEditor.impl.FileDocumentManagerImpl.doSaveDocument(FileDocumentManagerImpl.java:367)
	at com.intellij.openapi.fileEditor.impl.FileDocumentManagerImpl.saveDocuments(FileDocumentManagerImpl.java:287)
	at com.intellij.openapi.fileEditor.impl.FileDocumentManagerImpl.saveAllDocuments(FileDocumentManagerImpl.java:262)
	at com.intellij.openapi.fileEditor.impl.FileDocumentManagerImpl.saveAllDocuments(FileDocumentManagerImpl.java:255)
	at com.intellij.ide.actions.SaveAllAction.actionPerformed(SaveAllAction.kt:24)
	at com.intellij.openapi.keymap.impl.ActionProcessor.performAction(ActionProcessor.java:65)
	at com.intellij.openapi.keymap.impl.IdeKeyEventDispatcher$1.performAction(IdeKeyEventDispatcher.java:573)
	at com.intellij.openapi.keymap.impl.IdeKeyEventDispatcher.lambda$doPerformActionInner$10(IdeKeyEventDispatcher.java:706)
	at com.intellij.openapi.actionSystem.ex.ActionUtil.performDumbAwareWithCallbacks(ActionUtil.java:260)
	at com.intellij.openapi.keymap.impl.IdeKeyEventDispatcher.doPerformActionInner(IdeKeyEventDispatcher.java:702)
	at com.intellij.openapi.keymap.impl.IdeKeyEventDispatcher.processAction(IdeKeyEventDispatcher.java:645)
	at com.intellij.openapi.keymap.impl.IdeKeyEventDispatcher.processAction(IdeKeyEventDispatcher.java:584)
	at com.intellij.openapi.keymap.impl.IdeKeyEventDispatcher.processActionOrWaitSecondStroke(IdeKeyEventDispatcher.java:467)
	at com.intellij.openapi.keymap.impl.IdeKeyEventDispatcher.inInitState(IdeKeyEventDispatcher.java:456)
	at com.intellij.openapi.keymap.impl.IdeKeyEventDispatcher.dispatchKeyEvent(IdeKeyEventDispatcher.java:224)
	at com.intellij.ide.IdeEventQueue.dispatchKeyEvent(IdeEventQueue.java:804)
	at com.intellij.ide.IdeEventQueue._dispatchEvent(IdeEventQueue.java:754)
	at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$6(IdeEventQueue.java:447)
	at com.intellij.openapi.progress.impl.CoreProgressManager.computePrioritized(CoreProgressManager.java:818)
	at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$7(IdeEventQueue.java:446)
	at com.intellij.openapi.application.impl.ApplicationImpl.runIntendedWriteActionOnCurrentThread(ApplicationImpl.java:805)
	at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.java:498)
	at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
	at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.