Coder Social home page Coder Social logo

hyperdevs-team / poeditor-android-gradle-plugin Goto Github PK

View Code? Open in Web Editor NEW
51.0 51.0 26.0 364 KB

Gradle plug-in that enables importing PoEditor localized strings directly to an Android project

License: Apache License 2.0

Kotlin 99.16% Shell 0.84%
android android-localization android-poeditor android-strings android-translation android-translations gradle-kotlin gradle-plugin poeditor poeditor-api poeditor-string

poeditor-android-gradle-plugin's People

Contributors

adriangl avatar bogdanzurac avatar danielgallegovico avatar gustavaa avatar imartinez avatar martinakdaniel avatar nodejsjs avatar nokite avatar warrenfaith 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

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

poeditor-android-gradle-plugin's Issues

Unescape HTML tags being skipped during unescapeHtmlTags()

SW details (please complete the following information):

  • IDE version: [IntelliJ IDEA 2021.2.1 (Community Edition)
    Build #IC-212.5080.55, built on August 24, 2021]
  • Plug-in Version 2.0.0 - 2.4.0

Summary and background of the bug
Having a string like the following in POEditor:

<![CDATA[
  <br />
  <p><a href="mailto:[email protected]">ABC Email</a></p>
]]>

Makes the plugin to crash and never download the strings.

Steps to reproduce
Steps to reproduce the behaviour:

  1. Create a string with the above string in your POEditor project
  2. Try to sycn the string
  3. See error
> org.xml.sax.SAXParseException; lineNumber: 147; columnNumber: 235; The element type "p" must be terminated by the matching end-tag "</p>".

I followed the exception and found that
String.unescapeHtmlTags() doesn't do its job of replaces all html tags, mostly it will fail to replace
**&lt;a href="mailto:[email protected]"&gt;**ABC Email</a>

so I used this piece of code to fix the issue locally instead of changing the regex used:

fun String.unescapeHtmlTags(): String {
    return this.replace("&lt;", "<").replace("&gt;", ">")
}

and it's working very well now.

java.net.SocketTimeoutException while downloading translations xml file

SW details (please complete the following information):

  • IDE version: any version, also CI
  • Plug-in Version latest version, master, previous versions

Summary and background of the bug
The task importPoEditorStrings fails more than once for all devs with java.net.SocketTimeoutException. This happens way too often and also on CI which breaks our builds.

Steps to reproduce
Steps to reproduce the behavior:

  1. I set up the configuration
  2. I run the task
  3. See the socket timeout error at least once per day

Not-so-helpful stack trace:

* What went wrong:

Execution failed for task ':data-translations:importPoEditorStrings'.

> java.net.SocketTimeoutException: timeout

Expected behavior
Translations should download unless the server is actually down

Current behavior
Task fails to download translations quite often due to SocketTimeoutException

Additional context
Add any other context about the problem here.

Create proper guidelines and setup instructions for contributors

Summary and context of the enhancement
It would be handy to create some guidelines for setting up the project and how to submit contributions (apart from the PR templates)

Suggested implementation
We should take a look to how open-source projects do this so we can have an idea of what is important for contributors to have in the guidelines.

Language with empty translations

SW details (please complete the following information):

  • IDE version: Android Studio 4.1.1
  • Plug-in Version 1.4.2

Summary and background of the bug
Languages with empty translations returns empty updated data string from POEditor API which causes an error.

JSON fetched from POEditor:

{
   "response":{
      "status":"success",
      "code":"200",
      "message":"OK"
   },
   "result":{
      "languages":[
         {
            "name":"English",
            "code":"en",
            "translations":2,
            "percentage":100,
            "updated":"2021-02-22T07:32:39+0000"
         },
         {
            "name":"German",
            "code":"de",
            "translations":0,
            "percentage":0,
            "updated":""
         }
      ]
   }
}

Steps to reproduce
Steps to reproduce the behavior:

  1. Set up empty language without translations in POEditor
  2. Try to download translations

Stacktrace

Caused by: java.text.ParseException: Unparseable date: ""
        at com.bq.poeditor.gradle.utils.DateJsonAdapter.fromJson(DateJsonAdapter.kt:39)
        at com.bq.poeditor.gradle.utils.DateJsonAdapter.fromJson(DateJsonAdapter.kt:29)

Expected behavior
Download empty translations without any problem.

Current behavior
Error occurs java.text.ParseException: Unparseable date: "".

Improper format

Great project. I am using to convert my strings from PoEditor. However, I am running into problems with the format of the generated values folders. For example,

values-zh-CN - android studio does not like the format and expects it the CH to be prefaced with an r. Further, any secondary region specifier should be prefaced with an r in my understanding.

Please help.

Add support for library modules

Summary and context of the enhancement
As per discussed in #17, with the removal of resDirPath and the obligation of only being able to use the plugin in application modules in version 1.0.0 of the plug-in, support for library modules was dropped since you could no longer set-up a custom path. This issue aims to add proper support for library modules, so we can have tasks to import PoEditor strings from both application and library modules, and call them using the usual ./gradlew :your_module:importPoEditorStrings.

Suggested implementation
Check if we can implement support for library projects using LibraryExtension and LibraryPlugin

Additional documentation
Check out

Html tags not encoded

Android doesn't support some of the Html tags (eg., <br/>) from string resource. In such cases, it has to be formatted using Html.fromHtml(), which expects the angle brackets in encoded format (&lt;), and set to the corresponding TextView in code. So, if we append html with the key, then the angle brackets have to be in encoded format.

invocation of 'Task.project' at execution time is unsupported

SW details (please complete the following information):

  • IDE version: Android Studio 2023.1.1 Patch 1
  • Plug-in Version 4.1.1 - 4.2.0
  • Gradle Version 8.5

Summary and background of the bug

When running the importPoEditorStrings Gradle task, after the files are properly downloaded and saved:

Retrieving project languages...
Available languages: [en]
Retrieving translation file URL for language code: en
Downloading file from URL: https://api.poeditor.com/v2/download/file/...
Saving strings to /Users/.../Workspace/.../app/src/main/res/values

Gradle throws the following error:

FAILURE: Build failed with an exception.

* What went wrong:
Configuration cache problems found in this build.

- Task `:app:importPoEditorStrings` of type `com.hyperdevs.poeditor.gradle.tasks.ImportPoEditorStringsTask`: invocation of 'Task.project' at execution time is unsupported.
  See https://docs.gradle.org/8.5/userguide/configuration_cache.html#config_cache:requirements:use_project_during_execution

I've tested this on Gradle 8.2 and 8.5, same result.
I've tested the following library versions:

  • 4.0.0 doesn't throw any errors, it works perfectly
  • 4.1.0 unfortunately breaks Gradle sync, so I couldn't test it at all
  • 4.1.1 and 4.2.0 throw the error

Remove/Skip untranslated strings from XML

Summary and context of the enhancement
When importing translations from POEditor, terms that are currently not translated to a given language must be removed.

Android Studio/Gradle's default behavior on blank but defined strings is to actually blank the text out instead of using the default (from values). This causes the app to crash, notably if it uses placeholders.

Multiply projects support

Support for several poeditor project ids
We have split all our strings to several poeditor projects - analytics, links, common strings. It will be great to support several projectId's in configuration.

Some emojis are html encoded

SW details (please complete the following information):

  • IDE version: Android Studio Electric Eel | 2022.1.1
  • Plug-in Version 3.0.0

Summary and background of the bug
We use a lot of emojis on poeditor and when we import terms some emojis are html encoded.
Android Studio is working great with emojis and it would be nice and easier to read if all emojis was not html encoded.

For exemple:

<string name="term_with_emoji">"❤️"</string> 
<string name="term_with_emoji_encoded">"&#x1f622;"</string>

Steps to reproduce
Steps to reproduce the behavior:

  1. Add two terms on poeditor, one with ❤️ (heart emoji) and another with 📍 (pushpin emoji)
  2. Sync the strings
  3. Check generated strings.xm files

Expected behavior
Does not html encode emojis for better readability

Current behavior
Some emojis (but not all) are html encode

Add support for multiple build types

Summary and context of the enhancement
Add support for multiple build types' translations in the plugin, so we can import different projects for them.

Suggested implementation
The ideal thing would be to get some configuration like this so we can easily configure it in Gradle scripts:

poEditor {
    // General configuration, in case we don't define build type specific configuration
    apiToken = "your_api_token"
    projectId = 12345
    defaultLang = "en"
    resDirPath = "${project.rootDir}/app/src/main/res"

    // Configuration for flavor1, overrides general configuration
    flavor1 {
        apiToken = "your_api_token"
        projectId = 23456
        defaultLang = "en"
        resDirPath = "${project.rootDir}/app/src/flavor1/res"
    }

    ...
}

Additional documentation
We should check other Gradle plugins so we can get info about how to do this.

Indonesian is exported to values-id instead of values-in

The strings.xml file for Indonesian is exported to values-id but changing the device language to Indonesian has no effect on the app. If the file is in values-in however, it works as expected.
Another thing I noticed is that both id and in are listed as Indonesian in Android Studio's Translations Editor, but on the phone itself only in is working. This seems to be more of a Java/Android issue, since the official ISO 639-1 is in fact id.

I think this is also the case for Hebrew and Yiddish: https://developer.android.com/reference/java/util/Locale.html#Locale(java.lang.String)

ISO 639 is not a stable standard; some of the language codes it defines (specifically "iw", "ji", and "in") have changed. This constructor accepts both the old codes ("iw", "ji", and "in") and the new codes ("he", "yi", and "id"), but all other API on Locale will return only the OLD codes.

  • IDE version: Android Studio 2021.2.1
  • Plug-in Version: 3.0.0
  • Android version: 12

Disable tablet generation

The XML parser throws some exceptions because of this tablet generation.
Mainly, when there are HTML Strings

Text must not be null or empty

Though my project contains non-empty strings, the plugin throws the following error. If you want I can share my poeditor credentials privately with you. I'm using com.github.imartinez:poeditor-android-gradle-plugin:0.2.6. But, I think that doesn't matter, because I encountered the same error with com.github.bq:poeditor-android-gradle-plugin:0.2.5 also.

`:app:importPoEditorStrings FAILED

FAILURE: Build failed with an exception.

  • What went wrong:
    Execution failed for task ':app:importPoEditorStrings'.

Text must not be null or empty

  • Try:
    Run with --info or --debug option to get more log output.

  • Exception is:
    org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':app:importPoEditorStrings'.
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:84)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:55)
    at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:62)
    at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:58)
    at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:88)
    at org.gradle.api.internal.tasks.execution.ResolveTaskArtifactStateTaskExecuter.execute(ResolveTaskArtifactStateTaskExecuter.java:46)
    at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:51)
    at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:54)
    at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:43)
    at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:34)
    at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker$1.execute(DefaultTaskGraphExecuter.java:236)
    at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker$1.execute(DefaultTaskGraphExecuter.java:228)
    at org.gradle.internal.Transformers$4.transform(Transformers.java:169)
    at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:106)
    at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:61)
    at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:228)
    at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:215)
    at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.processTask(AbstractTaskPlanExecutor.java:77)
    at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.run(AbstractTaskPlanExecutor.java:58)
    at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor.process(DefaultTaskPlanExecutor.java:32)
    at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter.execute(DefaultTaskGraphExecuter.java:113)
    at org.gradle.execution.SelectedTaskExecutionAction.execute(SelectedTaskExecutionAction.java:37)
    at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:37)
    at org.gradle.execution.DefaultBuildExecuter.access$000(DefaultBuildExecuter.java:23)
    at org.gradle.execution.DefaultBuildExecuter$1.proceed(DefaultBuildExecuter.java:43)
    at org.gradle.execution.DryRunBuildExecutionAction.execute(DryRunBuildExecutionAction.java:32)
    at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:37)
    at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:30)
    at org.gradle.initialization.DefaultGradleLauncher$3.execute(DefaultGradleLauncher.java:196)
    at org.gradle.initialization.DefaultGradleLauncher$3.execute(DefaultGradleLauncher.java:193)
    at org.gradle.internal.Transformers$4.transform(Transformers.java:169)
    at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:106)
    at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:56)
    at org.gradle.initialization.DefaultGradleLauncher.doBuildStages(DefaultGradleLauncher.java:193)
    at org.gradle.initialization.DefaultGradleLauncher.doBuild(DefaultGradleLauncher.java:119)
    at org.gradle.initialization.DefaultGradleLauncher.run(DefaultGradleLauncher.java:102)
    at org.gradle.launcher.exec.GradleBuildController.run(GradleBuildController.java:71)
    at org.gradle.tooling.internal.provider.ExecuteBuildActionRunner.run(ExecuteBuildActionRunner.java:28)
    at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35)
    at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:41)
    at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:26)
    at org.gradle.tooling.internal.provider.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:75)
    at org.gradle.tooling.internal.provider.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:49)
    at org.gradle.tooling.internal.provider.ServicesSetupBuildActionExecuter.execute(ServicesSetupBuildActionExecuter.java:44)
    at org.gradle.tooling.internal.provider.ServicesSetupBuildActionExecuter.execute(ServicesSetupBuildActionExecuter.java:29)
    at org.gradle.launcher.daemon.server.exec.ExecuteBuild.doBuild(ExecuteBuild.java:67)
    at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
    at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
    at org.gradle.launcher.daemon.server.exec.WatchForDisconnection.execute(WatchForDisconnection.java:47)
    at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
    at org.gradle.launcher.daemon.server.exec.ResetDeprecationLogger.execute(ResetDeprecationLogger.java:26)
    at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
    at org.gradle.launcher.daemon.server.exec.RequestStopIfSingleUsedDaemon.execute(RequestStopIfSingleUsedDaemon.java:34)
    at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
    at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.call(ForwardClientInput.java:74)
    at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.call(ForwardClientInput.java:72)
    at org.gradle.util.Swapper.swap(Swapper.java:38)
    at org.gradle.launcher.daemon.server.exec.ForwardClientInput.execute(ForwardClientInput.java:72)
    at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
    at org.gradle.launcher.daemon.server.exec.LogAndCheckHealth.execute(LogAndCheckHealth.java:55)
    at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
    at org.gradle.launcher.daemon.server.exec.LogToClient.doBuild(LogToClient.java:60)
    at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
    at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
    at org.gradle.launcher.daemon.server.exec.EstablishBuildEnvironment.doBuild(EstablishBuildEnvironment.java:72)
    at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
    at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
    at org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy$1.run(StartBuildOrRespondWithBusy.java:50)
    at org.gradle.launcher.daemon.server.DaemonStateCoordinator$1.run(DaemonStateCoordinator.java:297)
    at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:54)
    at org.gradle.internal.concurrent.StoppableExecutorImpl$1.run(StoppableExecutorImpl.java:40)
    Caused by: java.lang.IllegalArgumentException: Text must not be null or empty
    at com.bq.gradle.ImportPoEditorStringsTask.importPoEditorStrings(ImportPoEditorStringsTask.groovy:58)
    at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:73)
    at org.gradle.api.internal.project.taskfactory.DefaultTaskClassInfoStore$StandardTaskAction.doExecute(DefaultTaskClassInfoStore.java:141)
    at org.gradle.api.internal.project.taskfactory.DefaultTaskClassInfoStore$StandardTaskAction.execute(DefaultTaskClassInfoStore.java:134)
    at org.gradle.api.internal.project.taskfactory.DefaultTaskClassInfoStore$StandardTaskAction.execute(DefaultTaskClassInfoStore.java:123)
    at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:632)
    at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:615)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:95)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:76)
    ... 70 more

BUILD FAILED`

How can I add the plugin with the new gradle format

Hi there,

Im trying to import the plugin with the new Gradle format like bellow,

plugins {
    id 'com.android.application' version "$gradlePluginVersion" apply false
    id 'com.android.library' version "$gradlePluginVersion" apply false
    id 'org.jetbrains.kotlin.android' version "$kotlinPluginVersion" apply false
  
    id 'com.github.hyperdevs-team.poeditor-android-gradle-plugin' version "$poEditorPluginVersion" apply false
}

But Im always getting the bellow error:

Plugin [id: 'com.github.hyperdevs-team.poeditor-android-gradle-plugin', version: '3.4.0', apply: false] was not found in any of the following sources:

What is the correct ID?

Thank you,

Best regards,
Bernardo

Have the import the ability to ignore comments

Summary and context of the enhancement
Hello guys, in the configuration of the import

poEditor {
    apiToken = "your_api_token"
    projectId = 12345
    defaultLang = "en"
}

I am missing a config property for comments.
My strings import is always with them included, which makes the final resource file kinda bloated.

<string>abc</string>
<!--comment related to "def"-->
<string>def</string>

It is only comments, which is not crucial, but still you can introduce a lot of unnecessary things like TODOs, unrelated information, etc.
I haven't found how to omit them in the import.

Suggested implementation
Just a boolean property on the config would be great.

poEditor {
    apiToken = "your_api_token"
    projectId = 12345
    defaultLang = "en"
    **importComments = false**
}

Thanks!

Dekekt output is not clear when it fails

SW details (please complete the following information):

  • Plug-in Version: 2.2.1

Summary and background of the bug
As reported by @nokite in #37:

Btw I often have trouble with detekt. Like now when merging master into my branch.
When there's a problem and the commit/merge commit is blocked, the error output is hard to read, it's all in one line 🙂
Maybe it's not correctly set up on my machine, didn't spend time on this.

Here's some output. In this case it's actually pretty short, but normally it also mentions some formatting/complexity warnings etc. (and it's all in one line)

Couldn't check the working tree for unmerged files because of an error. tput: No value for $TERM and no -T specified tput: No value for $TERM and no -T specified tput: No value for $TERM and no -T specified tput: No value for $TERM and no -T specified Running detekt > Task :detekt UP-TO-DATE Deprecated Gradle features were used in this build, making it incompatible with Gradle 7.0. Use '--warning-mode all' to show the individual deprecation warnings. See https://docs.gradle.org/6.9/userguide/command_line_interface.html#sec:command_line_warnings BUILD SUCCESSFUL in 814ms 1 actionable task: 1 up-to-date Your code is properly formatted! could not read log file '/Users/.../poeditor-android-gradle-plugin/.git/MERGE_MSG': No such file or directory

ImportPoEditorStrings throws error when retrieving strings. No result coming in Json.

`./gradlew importPoEditorStrings --stacktrace

Task :myProject:importPoEditorStrings FAILED
Retrieving project languages...
An error happened when retrieving strings from project. Please review the plug-in's input parameters and try again

FAILURE: Build failed with an exception.

  • What went wrong:
    Execution failed for task ':myProject:importPoEditorStrings'.

Required value 'result' missing at $

  • Try:

Run with --info or --debug option to get more log output.
Run with --scan to get full insights.

  • Exception is:
    org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':myProject:importPoEditorStrings'.
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.lambda$executeIfValid$1(ExecuteActionsTaskExecuter.java:145)
    at org.gradle.internal.Try$Failure.ifSuccessfulOrElse(Try.java:282)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeIfValid(ExecuteActionsTaskExecuter.java:143)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:131)
    at org.gradle.api.internal.tasks.execution.CleanupStaleOutputsExecuter.execute(CleanupStaleOutputsExecuter.java:77)
    at org.gradle.api.internal.tasks.execution.FinalizePropertiesTaskExecuter.execute(FinalizePropertiesTaskExecuter.java:46)
    at org.gradle.api.internal.tasks.execution.ResolveTaskExecutionModeExecuter.execute(ResolveTaskExecutionModeExecuter.java:51)
    at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:57)
    at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:56)
    at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:36)
    at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.executeTask(EventFiringTaskExecuter.java:77)
    at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:55)
    at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:52)
    at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
    at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:199)
    at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
    at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
    at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157)
    at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
    at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
    at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:73)
    at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter.execute(EventFiringTaskExecuter.java:52)
    at org.gradle.execution.plan.LocalTaskNodeExecutor.execute(LocalTaskNodeExecutor.java:74)
    at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:402)
    at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:389)
    at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:382)
    at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:368)
    at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.lambda$run$0(DefaultPlanExecutor.java:127)
    at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.execute(DefaultPlanExecutor.java:191)
    at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.executeNextNode(DefaultPlanExecutor.java:182)
    at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.run(DefaultPlanExecutor.java:124)
    at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
    at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
    at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:61)
    Caused by: com.squareup.moshi.JsonDataException: Required value 'result' missing at $
    at com.squareup.moshi.internal.Util.missingProperty(Util.java:649)
    at com.squareup.moshi.kotlin.reflect.KotlinJsonAdapter.fromJson(KotlinJsonAdapter.kt:103)
    at com.squareup.moshi.internal.NullSafeJsonAdapter.fromJson(NullSafeJsonAdapter.java:41)
    at retrofit2.converter.moshi.MoshiResponseBodyConverter.convert(MoshiResponseBodyConverter.java:46)
    at retrofit2.converter.moshi.MoshiResponseBodyConverter.convert(MoshiResponseBodyConverter.java:27)
    at retrofit2.OkHttpCall.parseResponse(OkHttpCall.java:243)
    at retrofit2.OkHttpCall.execute(OkHttpCall.java:204)
    at com.hyperdevs.poeditor.gradle.network.PoEditorApiControllerImpl.getProjectLanguages(PoEditorApiController.kt:54)
    at com.hyperdevs.poeditor.gradle.PoEditorStringsImporter.importPoEditorStrings(PoEditorStringsImporter.kt:101)
    at com.hyperdevs.poeditor.gradle.tasks.ImportPoEditorStringsTask.importPoEditorStrings(ImportPoEditorStringsTask.kt:77)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:104)
    at org.gradle.api.internal.project.taskfactory.StandardTaskAction.doExecute(StandardTaskAction.java:58)
    at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:51)
    at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:29)
    at org.gradle.api.internal.tasks.execution.TaskExecution$2.run(TaskExecution.java:239)
    at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29)
    at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26)
    at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
    at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
    at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157)
    at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
    at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:47)
    at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:68)
    at org.gradle.api.internal.tasks.execution.TaskExecution.executeAction(TaskExecution.java:224)
    at org.gradle.api.internal.tasks.execution.TaskExecution.executeActions(TaskExecution.java:207)
    at org.gradle.api.internal.tasks.execution.TaskExecution.executeWithPreviousOutputFiles(TaskExecution.java:190)
    at org.gradle.api.internal.tasks.execution.TaskExecution.execute(TaskExecution.java:168)
    at org.gradle.internal.execution.steps.ExecuteStep.executeInternal(ExecuteStep.java:89)
    at org.gradle.internal.execution.steps.ExecuteStep.access$000(ExecuteStep.java:40)
    at org.gradle.internal.execution.steps.ExecuteStep$1.call(ExecuteStep.java:53)
    at org.gradle.internal.execution.steps.ExecuteStep$1.call(ExecuteStep.java:50)
    at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
    at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:199)
    at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
    at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
    at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157)
    at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
    at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
    at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:73)
    at org.gradle.internal.execution.steps.ExecuteStep.execute(ExecuteStep.java:50)
    at org.gradle.internal.execution.steps.ExecuteStep.execute(ExecuteStep.java:40)
    at org.gradle.internal.execution.steps.RemovePreviousOutputsStep.execute(RemovePreviousOutputsStep.java:68)
    at org.gradle.internal.execution.steps.RemovePreviousOutputsStep.execute(RemovePreviousOutputsStep.java:38)
    at org.gradle.internal.execution.steps.ResolveInputChangesStep.execute(ResolveInputChangesStep.java:48)
    at org.gradle.internal.execution.steps.ResolveInputChangesStep.execute(ResolveInputChangesStep.java:36)
    at org.gradle.internal.execution.steps.CancelExecutionStep.execute(CancelExecutionStep.java:41)
    at org.gradle.internal.execution.steps.TimeoutStep.executeWithoutTimeout(TimeoutStep.java:74)
    at org.gradle.internal.execution.steps.TimeoutStep.execute(TimeoutStep.java:55)
    at org.gradle.internal.execution.steps.CreateOutputsStep.execute(CreateOutputsStep.java:51)
    at org.gradle.internal.execution.steps.CreateOutputsStep.execute(CreateOutputsStep.java:29)
    at org.gradle.internal.execution.steps.CaptureStateAfterExecutionStep.execute(CaptureStateAfterExecutionStep.java:61)
    at org.gradle.internal.execution.steps.CaptureStateAfterExecutionStep.execute(CaptureStateAfterExecutionStep.java:42)
    at org.gradle.internal.execution.steps.BroadcastChangingOutputsStep.execute(BroadcastChangingOutputsStep.java:60)
    at org.gradle.internal.execution.steps.BroadcastChangingOutputsStep.execute(BroadcastChangingOutputsStep.java:27)
    at org.gradle.internal.execution.steps.BuildCacheStep.executeWithoutCache(BuildCacheStep.java:188)
    at org.gradle.internal.execution.steps.BuildCacheStep.lambda$execute$1(BuildCacheStep.java:75)
    at org.gradle.internal.Either$Right.fold(Either.java:175)
    at org.gradle.internal.execution.caching.CachingState.fold(CachingState.java:59)
    at org.gradle.internal.execution.steps.BuildCacheStep.execute(BuildCacheStep.java:73)
    at org.gradle.internal.execution.steps.BuildCacheStep.execute(BuildCacheStep.java:48)
    at org.gradle.internal.execution.steps.StoreExecutionStateStep.execute(StoreExecutionStateStep.java:38)
    at org.gradle.internal.execution.steps.StoreExecutionStateStep.execute(StoreExecutionStateStep.java:27)
    at org.gradle.internal.execution.steps.RecordOutputsStep.execute(RecordOutputsStep.java:36)
    at org.gradle.internal.execution.steps.RecordOutputsStep.execute(RecordOutputsStep.java:22)
    at org.gradle.internal.execution.steps.SkipUpToDateStep.executeBecause(SkipUpToDateStep.java:109)
    at org.gradle.internal.execution.steps.SkipUpToDateStep.lambda$execute$2(SkipUpToDateStep.java:56)
    at org.gradle.internal.execution.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:56)
    at org.gradle.internal.execution.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:38)
    at org.gradle.internal.execution.steps.ResolveChangesStep.execute(ResolveChangesStep.java:73)
    at org.gradle.internal.execution.steps.ResolveChangesStep.execute(ResolveChangesStep.java:44)
    at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:37)
    at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:27)
    at org.gradle.internal.execution.steps.ResolveCachingStateStep.execute(ResolveCachingStateStep.java:89)
    at org.gradle.internal.execution.steps.ResolveCachingStateStep.execute(ResolveCachingStateStep.java:50)
    at org.gradle.internal.execution.steps.ValidateStep.execute(ValidateStep.java:114)
    at org.gradle.internal.execution.steps.ValidateStep.execute(ValidateStep.java:57)
    at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.execute(CaptureStateBeforeExecutionStep.java:76)
    at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.execute(CaptureStateBeforeExecutionStep.java:50)
    at org.gradle.internal.execution.steps.SkipEmptyWorkStep.lambda$execute$2(SkipEmptyWorkStep.java:93)
    at org.gradle.internal.execution.steps.SkipEmptyWorkStep.execute(SkipEmptyWorkStep.java:93)
    at org.gradle.internal.execution.steps.SkipEmptyWorkStep.execute(SkipEmptyWorkStep.java:34)
    at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsStartedStep.execute(MarkSnapshottingInputsStartedStep.java:38)
    at org.gradle.internal.execution.steps.LoadPreviousExecutionStateStep.execute(LoadPreviousExecutionStateStep.java:43)
    at org.gradle.internal.execution.steps.LoadPreviousExecutionStateStep.execute(LoadPreviousExecutionStateStep.java:31)
    at org.gradle.internal.execution.steps.AssignWorkspaceStep.lambda$execute$0(AssignWorkspaceStep.java:40)
    at org.gradle.api.internal.tasks.execution.TaskExecution$3.withWorkspace(TaskExecution.java:284)
    at org.gradle.internal.execution.steps.AssignWorkspaceStep.execute(AssignWorkspaceStep.java:40)
    at org.gradle.internal.execution.steps.AssignWorkspaceStep.execute(AssignWorkspaceStep.java:30)
    at org.gradle.internal.execution.steps.IdentityCacheStep.execute(IdentityCacheStep.java:37)
    at org.gradle.internal.execution.steps.IdentityCacheStep.execute(IdentityCacheStep.java:27)
    at org.gradle.internal.execution.steps.IdentifyStep.execute(IdentifyStep.java:44)
    at org.gradle.internal.execution.steps.IdentifyStep.execute(IdentifyStep.java:33)
    at org.gradle.internal.execution.impl.DefaultExecutionEngine$1.execute(DefaultExecutionEngine.java:76)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeIfValid(ExecuteActionsTaskExecuter.java:142)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:131)
    at org.gradle.api.internal.tasks.execution.CleanupStaleOutputsExecuter.execute(CleanupStaleOutputsExecuter.java:77)
    at org.gradle.api.internal.tasks.execution.FinalizePropertiesTaskExecuter.execute(FinalizePropertiesTaskExecuter.java:46)
    at org.gradle.api.internal.tasks.execution.ResolveTaskExecutionModeExecuter.execute(ResolveTaskExecutionModeExecuter.java:51)
    at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:57)
    at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:56)
    at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:36)
    at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.executeTask(EventFiringTaskExecuter.java:77)
    at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:55)
    at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:52)
    at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
    at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:199)
    at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
    at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
    at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157)
    at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
    at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
    at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:73)
    at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter.execute(EventFiringTaskExecuter.java:52)
    at org.gradle.execution.plan.LocalTaskNodeExecutor.execute(LocalTaskNodeExecutor.java:74)
    at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:402)
    at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:389)
    at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:382)
    at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:368)
    at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.lambda$run$0(DefaultPlanExecutor.java:127)
    at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.execute(DefaultPlanExecutor.java:191)
    at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.executeNextNode(DefaultPlanExecutor.java:182)
    at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.run(DefaultPlanExecutor.java:124)
    at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
    at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
    at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:61)
    `

Add an ability to disable unescapeHtmlTags() formatting

Summary and context of the enhancement
In our project we use html tags combined with format strings. That means that tags should be escaped. It would be great to have that option.

Suggested implementation
Add an attribute unescapeHtmlTags to poEditor section with default value true. And than in XmlPostProcessor.formatTranslationString() check that attribute

Additional documentation
About
https://developer.android.com/guide/topics/resources/string-resource.html#StylingWithHTML

Remove JCenter before February 2022

SW details:

  • Plug-in Version 2.4.1

Summary and background of the bug
JCenter may stop working in February 2022, so it should be removed from the project. Any dependencies should be fetched from other repositories.

The shutdown date of the repository itself is not clear. In reality it might keep working in read-only mode for a longer time. But no guarantees are given after February.
Furthermore, Gradle 8 will remove jcenter().

https://blog.gradle.org/jcenter-shutdown

Setting order is not working

SW details (please complete the following information):

  • IDE version: Android Studio Flamingo v9
  • Plug-in Version - 3.1.0

Summary and background of the bug
In the documentation it's mentioned that it's possible to send order in the parameters but I belive in the latest gradle settings it's not working because it's missing a setter. Something like this for example:
fun setDefaultLang(value: String) = defaultLang.set(value)

This is not available for order

Steps to reproduce
Steps to reproduce the behavior:

  1. Add the "order = "terms"" in the poEditor block.
  2. Sync the project
  3. See error

A problem occurred evaluating project ':app'.

Could not set unknown property 'order' for extension 'poEditor' of type com.hyperdevs.poeditor.gradle.PoEditorPluginExtension.

Expected behavior
Value would be set in the request to poeditor and terms would arrive ordered

Current behavior
Crashes. Exception in pasted above.

Additional context
Nothing else.

Simplified and Traditional Chinese are downloaded to folders not accepted by Android

SW details (please complete the following information):

  • Plug-in Version 1.4.1

Gradle 6.2

Build time: 2020-02-17 08:32:01 UTC
Revision: 61d3320259a1a0d31519bf208eb13741679a742f

Kotlin: 1.3.61
Groovy: 2.5.8
Ant: Apache Ant(TM) version 1.10.7 compiled on September 1 2019
JVM: 1.8.0_231 (Oracle Corporation 25.231-b11)
OS: Mac OS X 10.16 x86_64

Summary and background of the bug
Simplified Chinese is downloaded to values-zh-rHANS and Traditional Chinese to values-zh-tHANT. They should probably be in values-b+zh+Hans and values-b+zh+Hant respectively.

Steps to reproduce
Steps to reproduce the behavior:

  1. Add languages Simplified Chinese and Traditional Chinese to your POEditor project
  2. Download translations using this gradle plugin

Expected behavior
Translations should probably be in values-b+zh+Hans and values-b+zh+Hant respectively.

Current behavior
Simplified Chinese is downloaded to values-zh-rHANS and Traditional Chinese to values-zh-tHANT

Build fail after Android Gradle Plugin 7.1.0 update

SW details (please complete the following information):

  • IDE version: Android Studio Bumbebee 1.1.0
  • Plug-in Version: 2.4.2

Summary and background of the bug

image

After updating the android gradle plugin from 7.0.4 to 7.1.0, an error occurs when building.
I think ApplicationAndroidComponentsExtension was deprecated.

Steps to reproduce
Steps to reproduce the behavior:

  1. Android Gradle Plugin "com.android.tools.build:gradle:7.1.0" update
  2. Build

Html based strings wrapped by <![CDATA[ ]]> on POEditor are imported without <![CDATA[ ]]> via plugin

SW details

  • IDE version: Android Studio Arctic Fox 2020.3.1
  • Plug-in Version: 2.2.1 - 2.4.0

Summary and background of the bug
Html based strings wrapped by <![CDATA[ ]]> on POEditor are imported without <![CDATA[ ]]> via plugin

Steps to reproduce
Steps to reproduce the behavior:

  1. Add html based string to POEditor project
    e.g: <![CDATA[Some text<a href="%1$s">Link</a> text text]]>
  2. Import the strings in to project
  3. <![CDATA[ ]]> is missed
    e.g:
    <string name="test_string_id">"Some text<a href="%1$s">Link</a> text text"</string>

Expected behavior
Imported strings should contain <![CDATA[ ]]>

Current behavior
<![CDATA[ ]]> is missed

Additional context
When strings are exported via POEditor web page, they contain <![CDATA[ ]]>

Option for disabling HTML entity unescaping

Summary and context of the enhancement
This is a resurrection of the issue #49. In our project we use HTML tags combined with format strings. That means that tags should be escaped. It would be great to have that option.

Suggested implementation
Add an attribute unescapeHtmlTags to poEditor section with default value true, and enable/disable string escaping based on this value.

Additional documentation
https://developer.android.com/guide/topics/resources/string-resource.html#StylingWithHTML

In some cases, however, you may want to create a styled text resource that is also used as a format string. Normally, this doesn't work [...] The work-around to this is to write the HTML tags with escaped entities.

Add support to export by tag

Summary and context of the enhancement
As an user I want to download the strings for specific module based on a given tag(s).

Suggested implementation
Added a new configuration to the poEditor receiving an array of tags.
On the poEditor API request send the list of tags to poEditor API, poEditor will filter the strings by tag(s)

Export Documentation

Multiple tags intersection doesn't work

SW details (please complete the following information):

  • IDE version: AS Giraffe
  • Plug-in Version 3.4.1

Summary and background of the bug
Tags intersection doesn't work when specifying a list of tags. The plugin just pulls in all strings, not an intersection of the tags as it's supposed to.

I assume this is caused by the way the tags are being sent using Retrofit. They should be sent as tags : ["tagA", "tagB"] (https://poeditor.com/docs/api#projects_export_example_1_button). I haven't been able to check it, but I assume currently they are being sent as tags : tagA, tagB

Steps to reproduce
Steps to reproduce the behavior:

  1. Set up 2 strings on the PoEditor web app using 3 tags (string 1 being added to tags A & B, string 2 being added to tags A & C)
  2. Set up the plugin config to pull in tags A & B
  3. Run the import

Expected behavior
Only string 1 should be pulled.

Current behavior
Currently both strings are pulled.

Issue when applying the plugin

SW details (please complete the following information):

  • IDE version: Android Studio Giraffe | 2022.3.1 Patch 2
  • Plug-in Version 4.1.0

Summary and background of the bug
When applying the plugin to a project I get the following error:

A problem occurred configuring project ':app'.
> Cannot query the value of extension 'poEditor' property 'enabled' because it has no value available.

Steps to reproduce
Steps to reproduce the behavior:

  1. Sync project with gradle files

I have replicated this on my work project and also tired it in a new bare bones Android project. I have attached the project for replication purposes.

PlaygroundApplication.zip

If you need any more info let me know.

Expected behavior
The sync should pass without error.

Additional context
Add any other context about the problem here.

Not working

`* What went wrong:
Execution failed for task ':app:importPoEditorStrings'.

java.io.IOException: Cannot run program "curl": CreateProcess error=2, The system cannot find the file specified

  • Try:
    Run with --info or --debug option to get more log output.

  • Exception is:
    org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':app:importPoEditorStrings'.
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:84)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:55)
    at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:62)
    at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:58)
    at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:88)
    at org.gradle.api.internal.tasks.execution.ResolveTaskArtifactStateTaskExecuter.execute(ResolveTaskArtifactStateTaskExecuter.java:46)
    at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:51)
    at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:54)
    at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:43)
    at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:34)
    at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker$1.execute(DefaultTaskGraphExecuter.java:236)
    at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker$1.execute(DefaultTaskGraphExecuter.java:228)
    at org.gradle.internal.Transformers$4.transform(Transformers.java:169)
    at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:106)
    at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:61)
    at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:228)
    at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:215)
    at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.processTask(AbstractTaskPlanExecutor.java:77)
    at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.run(AbstractTaskPlanExecutor.java:58)
    at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor.process(DefaultTaskPlanExecutor.java:32)
    at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter.execute(DefaultTaskGraphExecuter.java:113)
    at org.gradle.execution.SelectedTaskExecutionAction.execute(SelectedTaskExecutionAction.java:37)
    at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:37)
    at org.gradle.execution.DefaultBuildExecuter.access$000(DefaultBuildExecuter.java:23)
    at org.gradle.execution.DefaultBuildExecuter$1.proceed(DefaultBuildExecuter.java:43)
    at org.gradle.execution.DryRunBuildExecutionAction.execute(DryRunBuildExecutionAction.java:32)
    at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:37)
    at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:30)
    at org.gradle.initialization.DefaultGradleLauncher$3.execute(DefaultGradleLauncher.java:196)
    at org.gradle.initialization.DefaultGradleLauncher$3.execute(DefaultGradleLauncher.java:193)
    at org.gradle.internal.Transformers$4.transform(Transformers.java:169)
    at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:106)
    at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:56)
    at org.gradle.initialization.DefaultGradleLauncher.doBuildStages(DefaultGradleLauncher.java:193)
    at org.gradle.initialization.DefaultGradleLauncher.doBuild(DefaultGradleLauncher.java:119)
    at org.gradle.initialization.DefaultGradleLauncher.run(DefaultGradleLauncher.java:102)
    at org.gradle.launcher.exec.GradleBuildController.run(GradleBuildController.java:71)
    at org.gradle.tooling.internal.provider.ExecuteBuildActionRunner.run(ExecuteBuildActionRunner.java:28)
    at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35)
    at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:41)
    at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:26)
    at org.gradle.tooling.internal.provider.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:75)
    at org.gradle.tooling.internal.provider.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:49)
    at org.gradle.tooling.internal.provider.ServicesSetupBuildActionExecuter.execute(ServicesSetupBuildActionExecuter.java:44)
    at org.gradle.tooling.internal.provider.ServicesSetupBuildActionExecuter.execute(ServicesSetupBuildActionExecuter.java:29)
    at org.gradle.launcher.daemon.server.exec.ExecuteBuild.doBuild(ExecuteBuild.java:67)
    at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
    at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
    at org.gradle.launcher.daemon.server.exec.WatchForDisconnection.execute(WatchForDisconnection.java:47)
    at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
    at org.gradle.launcher.daemon.server.exec.ResetDeprecationLogger.execute(ResetDeprecationLogger.java:26)
    at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
    at org.gradle.launcher.daemon.server.exec.RequestStopIfSingleUsedDaemon.execute(RequestStopIfSingleUsedDaemon.java:34)
    at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
    at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.call(ForwardClientInput.java:74)
    at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.call(ForwardClientInput.java:72)
    at org.gradle.util.Swapper.swap(Swapper.java:38)
    at org.gradle.launcher.daemon.server.exec.ForwardClientInput.execute(ForwardClientInput.java:72)
    at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
    at org.gradle.launcher.daemon.server.exec.LogAndCheckHealth.execute(LogAndCheckHealth.java:55)
    at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
    at org.gradle.launcher.daemon.server.exec.LogToClient.doBuild(LogToClient.java:60)
    at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
    at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
    at org.gradle.launcher.daemon.server.exec.EstablishBuildEnvironment.doBuild(EstablishBuildEnvironment.java:72)
    at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
    at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
    at org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy$1.run(StartBuildOrRespondWithBusy.java:50)
    at org.gradle.launcher.daemon.server.DaemonStateCoordinator$1.run(DaemonStateCoordinator.java:297)
    at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:54)
    at org.gradle.internal.concurrent.StoppableExecutorImpl$1.run(StoppableExecutorImpl.java:40)
    Caused by: org.gradle.api.UncheckedIOException: java.io.IOException: Cannot run program "curl": CreateProcess error=2, The system cannot find the file specified
    at org.gradle.internal.UncheckedException.throwAsUncheckedException(UncheckedException.java:43)
    at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:76)
    at org.gradle.api.internal.project.taskfactory.DefaultTaskClassInfoStore$StandardTaskAction.doExecute(DefaultTaskClassInfoStore.java:141)
    at org.gradle.api.internal.project.taskfactory.DefaultTaskClassInfoStore$StandardTaskAction.execute(DefaultTaskClassInfoStore.java:134)
    at org.gradle.api.internal.project.taskfactory.DefaultTaskClassInfoStore$StandardTaskAction.execute(DefaultTaskClassInfoStore.java:123)
    at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:632)
    at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:615)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:95)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:76)
    ... 70 more
    Caused by: java.io.IOException: Cannot run program "curl": CreateProcess error=2, The system cannot find the file specified
    at com.bq.gradle.ImportPoEditorStringsTask.importPoEditorStrings(ImportPoEditorStringsTask.groovy:57)
    at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:73)
    ... 77 more
    Caused by: java.io.IOException: CreateProcess error=2, The system cannot find the file specified
    ... 79 more
    `

Can you provide a fix asap?

Handle plurals' string resources

Summary and context of the enhancement
Right now the plugin doesn't handle Android plurals properly.

Plurals' syntax is slightly different from the usual <string> nodes, as they follow this structure:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <plurals
        name="plural_name">
        <item
            quantity=["zero" | "one" | "two" | "few" | "many" | "other"]
            >text_string</item>
    </plurals>
</resources>

We need to be able to provide the same functionality that we do for simple strings to plural strings.
It may also be handy to ensure that we add at least one number to the placeholders, but for the initial approach it might not be needed.

Suggested implementation
No suggested implementation.

Additional documentation
Android information about plurals string resources: https://developer.android.com/guide/topics/resources/string-resource#Plurals

Doubled "%"

SW details (please complete the following information):

  • IDE version: Android Studio 4.0.1
  • Plug-in Version: 1.0.0
  • System: Windows 10

Summary and background of the bug
All the occurrences of "%" are doubled.

Eg.

  • Authentication error: %s! -> Authentication error: %%s!
  • %1$s - %2$s -> %%1$s - %%2$s

Another problem: all the string have been put into quotation marks

Eg.

  • Profile -> "Profile"

Steps to reproduce
Just execute: gradlew importPoEditorStrings

Expected behavior
I expect that these parameters ("%") string stay unattached

Current behavior
All the occurrences of "%" are doubled.

2020-08-07 12_54_57-strings xml (C__Projects_Android_mv7-android_app_src_main_res_values)  Default C

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.