Skip to content

Commit

Permalink
Merge branch 'dev' into master
Browse files Browse the repository at this point in the history
# Conflicts:
#	README.md
#	gradle.properties
#	src/main/kotlin/cn/yiiguxing/plugin/translate/action/TranslateDocumentationAction.kt
#	src/main/kotlin/cn/yiiguxing/plugin/translate/documentation/HtmlTranslator.kt
#	src/main/kotlin/cn/yiiguxing/plugin/translate/documentation/TranslateDocumentationTask.kt
#	src/main/kotlin/cn/yiiguxing/plugin/translate/provider/TranslatingDocumentationProvider.kt
  • Loading branch information
YiiGuxing committed Aug 15, 2020
2 parents efb5ee9 + 2eaa839 commit 0d85bc0
Show file tree
Hide file tree
Showing 128 changed files with 423 additions and 166 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Change Log

## [v2.9.2](https://github.com/YiiGuxing/TranslationPlugin/tree/v2.9.2) (2020-08-15)

- 添加快速切换自动文档翻译的快捷键
- 修复了一些Bug

## [v2.9.1](https://github.com/YiiGuxing/TranslationPlugin/tree/v2.9.1) (2020-05-18)

- 增强了运行控制台的取词翻译
Expand Down
15 changes: 11 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,13 @@

翻译文档注释内容。默认显示在编辑器右键菜单上,光标在文档注释块内时可用。默认快捷键: (无)

- **Toggle Quick Documentation Translation**

快速文档中将文档内容在译文和原文之间切换。窗口聚焦于快速文档弹出窗或者文档工具窗口时可用。默认快捷键(同**Translate**):

- Windows - <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>Y</kbd>
- Mac OS - <kbd>Control</kbd> + <kbd>Meta</kbd> + <kbd>U</kbd>

- **Translate Text Component**

翻译一些文本组件(如快速文档、提示气泡、输入框……)中选中的文本,不支持自动取词。默认快捷键:
Expand Down Expand Up @@ -175,9 +182,9 @@

## Change Notes

## [v2.9.1](https://github.com/YiiGuxing/TranslationPlugin/tree/v2.9.1) (2020-05-18)
## [v2.9.2](https://github.com/YiiGuxing/TranslationPlugin/tree/v2.9.2) (2020-08-15)

- 增强了运行控制台的取词翻译
- 添加快速切换自动文档翻译的快捷键
- 修复了一些Bug

[完整的更新历史记录](./CHANGELOG.md)
Expand Down Expand Up @@ -215,13 +222,13 @@

`名字/昵称 [<网站>][:留言]`(网站与留言为可选部分,例子:`Yii.Guxing <github.com/YiiGuxing>:加油!`

您提供的名字、网站和捐赠总额将会被添加到[**捐赠者**][financial-contributors]列表中,列表将按捐赠总额列出前50名捐赠者
您提供的名字、网站和捐赠总额将会被添加到[**捐赠者**][financial-contributors]列表中。

邮箱地址:[yii.guxing@gmail.com](mailto:yii.guxing@gmail.com?subject=Donate&body=%E5%90%8D%E5%AD%97%2F%E6%98%B5%E7%A7%B0%3C%E7%BD%91%E7%AB%99%3E%EF%BC%9A%E6%82%A8%E7%9A%84%E7%95%99%E8%A8%80%0A%0A%E6%8D%90%E8%B5%A0%E9%87%91%E9%A2%9D%EF%BC%9A%0A%E6%94%AF%E4%BB%98%E5%B9%B3%E5%8F%B0%EF%BC%9A%E6%94%AF%E4%BB%98%E5%AE%9D%2F%E5%BE%AE%E4%BF%A1%E6%94%AF%E4%BB%98%0A%E6%94%AF%E4%BB%98%E5%AE%9D%E7%94%A8%E6%88%B7%E5%90%8D%2F%E5%BE%AE%E4%BF%A1%E7%94%A8%E6%88%B7%E5%90%8D%2F%E5%8D%95%E5%8F%B7%EF%BC%88%E5%90%8E5%E4%BD%8D%EF%BC%89%EF%BC%9A%0A%0A) (点击发送邮件)

**感谢您的支持!**

## 其他插件
## More Plugins

- [FIGlet](https://github.com/YiiGuxing/intellij-figlet)
- [Material Design Color Palette](https://github.com/YiiGuxing/material-design-color-palette)
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# suppress inspection "UnusedProperty" for whole file
version=2.9.1
version=2.9.2
buildNumber=
#buildNumber=SNAPSHOT
ideaVersion=IU-2019.3
Expand Down
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.2.2-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.6-all.zip
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
<grid row="0" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<icon value="icons/swap.png"/>
<iconTextGap value="0"/>
<text value=""/>
</properties>
Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/cn/yiiguxing/plugin/translate/Settings.kt
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ class Settings : PersistentStateComponent<Settings> {
*/
var targetLanguageSelection: TargetLanguageSelection = TargetLanguageSelection.DEFAULT

var translateDocumentation: Boolean = true
var translateDocumentation: Boolean = false

@Transient
private val settingsChangePublisher: SettingsChangeListener =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ import com.intellij.codeInsight.CodeInsightBundle
import com.intellij.codeInsight.documentation.DocumentationComponent
import com.intellij.codeInsight.documentation.DocumentationManager
import com.intellij.lang.documentation.DocumentationProvider
import com.intellij.notification.Notification
import com.intellij.notification.NotificationAction
import com.intellij.openapi.Disposable
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.editor.Editor
Expand Down Expand Up @@ -68,7 +71,7 @@ class TranslateDocumentationAction : PsiElementTranslateAction() {
return@executeOnPooledThread
}

val translatedDocumentation = getTranslatedDocumentation(doc)
val translatedDocumentation = TranslateService.translator.getTranslatedDocumentation(doc)
invokeLater {
val documentationComponent = documentationComponentRef.get() ?: return@invokeLater
val e = editorRef.get()?.takeUnless { it.isDisposed }
Expand Down Expand Up @@ -142,18 +145,26 @@ class TranslateDocumentationAction : PsiElementTranslateAction() {
private val LOGGER: Logger = Logger.getInstance(TranslateDocumentationAction::class.java)

fun logAndShowWarning(e: Throwable, project: Project?) {
LOGGER.w(e.message ?: "", e)
invokeLater {
LOGGER.w(e.message ?: "", e)
Notifications.showErrorNotification(
project,
NOTIFICATION_DISPLAY_ID,
"Documentation",
"Failed to translate documentation: ${e.message}",
e
e,
DisableAutoDocTranslationAction()
)
}
}

class DisableAutoDocTranslationAction : NotificationAction(message("translate.documentation.disable")) {
override fun actionPerformed(e: AnActionEvent, notification: Notification) {
Settings.translateDocumentation = false
notification.expire()
}
}

private val PsiElement.documentationProvider: DocumentationProvider?
get() = DocumentationManager.getProviderFromElement(this)

Expand Down Expand Up @@ -196,7 +207,7 @@ class TranslateDocumentationAction : PsiElementTranslateAction() {
}

size = sizeToSet
setUserData(if (!restore) listOf(sizeToSet.clone()) else null)
setUserData(if (!restore) listOf(sizeToSet.clone()) else emptyList())
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package cn.yiiguxing.plugin.translate.documentation
import cn.yiiguxing.plugin.translate.trans.GoogleTranslator
import cn.yiiguxing.plugin.translate.trans.Lang
import cn.yiiguxing.plugin.translate.trans.Translator
import cn.yiiguxing.plugin.translate.util.TranslateService
import com.intellij.codeInsight.documentation.DocumentationComponent
import org.jsoup.Jsoup
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
Expand All @@ -27,24 +27,31 @@ private const val HTML_HEAD_REPLACEMENT = "<${'$'}{tag} class='${'$'}{class}'>"

private val HTML_KIT = HTMLEditorKit()

fun getTranslatedDocumentation(documentation: String): String {
fun Translator.getTranslatedDocumentation(documentation: String): String {
val document = Jsoup.parse(documentation)
if (document.body().hasAttr(TRANSLATED_ATTR)) {
return documentation
}

val translator = TranslateService.translator
val translatedDocumentation = if (translator is GoogleTranslator) {
translator.getTranslatedDocumentation(document)
val translatedDocumentation = if (this is GoogleTranslator) {
getTranslatedDocumentation(document)
} else {
translator.getTranslatedDocumentation(document)
getTranslatedDocumentation(document)
}

translatedDocumentation.body().attributes().put(TRANSLATED_ATTR, null)

return translatedDocumentation.outerHtml().fixHtml()
}

/**
* 修复HTML格式。[DocumentationComponent]识别不了`attr="val"`的属性表达形式,只识别`attr='val'`的表达形式,导致样式显示异常。
*/
private fun String.fixHtml(): String = replace(
HTML_HEAD_REGEX,
HTML_HEAD_REPLACEMENT
)

private fun GoogleTranslator.getTranslatedDocumentation(document: Document): Document {
val body = document.body()
val definition = body.selectFirst(CSS_QUERY_DEFINITION)?.apply { remove() }
Expand All @@ -61,10 +68,9 @@ private fun GoogleTranslator.getTranslatedDocumentation(document: Document): Doc
}

// 翻译内容会带有原文与译文,分号包在 `i` 标签和 `b` 标签内,因此替换掉这两个标签以免影响到翻译后的处理。
val content = body.html().replaceTag(TAG_B, TAG_STRONG).replaceTag(
TAG_I,
TAG_EM
)
val content = body.html()
.replaceTag(TAG_B, TAG_STRONG)
.replaceTag(TAG_I, TAG_EM)
val translation =
if (content.isBlank()) ""
else translateDocumentation(content, Lang.AUTO, primaryLanguage).translation ?: ""
Expand All @@ -83,14 +89,6 @@ private fun GoogleTranslator.getTranslatedDocumentation(document: Document): Doc
return document
}

/**
* 修复HTML格式。[DocumentationComponent]识别不了`attr="val"`的属性表达形式,只识别`attr='val'`的表达形式,导致样式显示异常。
*/
private fun String.fixHtml(): String = replace(
HTML_HEAD_REGEX,
HTML_HEAD_REPLACEMENT
)

private fun String.replaceTag(targetTag: String, replacementTag: String): String {
return replace(Regex("<(?<pre>/??)$targetTag(?<pos>( .+?)*?)>"), "<${'$'}{pre}$replacementTag${'$'}{pos}>")
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package cn.yiiguxing.plugin.translate.documentation

import cn.yiiguxing.plugin.translate.action.TranslateDocumentationAction
import cn.yiiguxing.plugin.translate.trans.Translator
import cn.yiiguxing.plugin.translate.util.TranslateService
import com.intellij.openapi.progress.ProgressManager
import org.jetbrains.concurrency.runAsync
import java.util.concurrent.TimeoutException

class TranslateDocumentationTask(val text: String) {
class TranslateDocumentationTask(val text: String, val translator: Translator = TranslateService.translator) {

private val totalTimeToWaitMs = 3_000
private val timeToBlockMs = 100
Expand All @@ -14,7 +16,7 @@ class TranslateDocumentationTask(val text: String) {

//execute on a different thread outside read action
private val promise = runAsync {
getTranslatedDocumentation(text)
translator.getTranslatedDocumentation(text)
}

fun onSuccess(callback: (String) -> Unit) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package cn.yiiguxing.plugin.translate.provider

import cn.yiiguxing.plugin.translate.Settings
import cn.yiiguxing.plugin.translate.documentation.TranslateDocumentationTask
import cn.yiiguxing.plugin.translate.util.TranslateService
import com.intellij.codeInsight.documentation.DocumentationManager
import com.intellij.lang.documentation.DocumentationProviderEx
import com.intellij.psi.PsiElement
Expand Down Expand Up @@ -54,10 +55,11 @@ class TranslatingDocumentationProvider : DocumentationProviderEx() {
if (text.isNullOrEmpty()) return null

val lastTask = lastTranslation
val translator = TranslateService.translator

val task =
if (lastTask != null && lastTask.text == text) lastTask
else TranslateDocumentationTask(text)
if (lastTask != null && lastTask.translator.id == translator.id && lastTask.text == text) lastTask
else TranslateDocumentationTask(text, translator)

lastTranslation = task

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package cn.yiiguxing.plugin.translate.service

import cn.yiiguxing.plugin.translate.trans.Lang
import cn.yiiguxing.plugin.translate.trans.Translation
import cn.yiiguxing.plugin.translate.util.LruCache
import com.intellij.openapi.components.Service
import com.intellij.openapi.components.ServiceManager

@Service
class CacheService {

private val memoryCache = LruCache<CacheKey, Translation>(1024)

fun putMemoryCache(text: String, srcLang: Lang, targetLang: Lang, translatorId: String, translation: Translation) {
memoryCache.put(CacheKey(text, srcLang, targetLang, translatorId), translation)
if (Lang.AUTO == srcLang) {
memoryCache.put(CacheKey(text, translation.srcLang, targetLang, translatorId), translation)
}
if (Lang.AUTO == targetLang) {
memoryCache.put(CacheKey(text, srcLang, translation.targetLang, translatorId), translation)
}
if (Lang.AUTO == srcLang && Lang.AUTO == targetLang) {
memoryCache.put(CacheKey(text, translation.srcLang, translation.targetLang, translatorId), translation)
}
}

fun getMemoryCache(text: String, srcLang: Lang, targetLang: Lang, translatorId: String): Translation? {
return memoryCache[CacheKey(text, srcLang, targetLang, translatorId)]
}

fun getMemoryCacheSnapshot(): Map<CacheKey, Translation> {
return memoryCache.snapshot
}

/**
* CacheKey
*/
data class CacheKey(val text: String, val srcLang: Lang, val targetLang: Lang, val translator: String = "unknown")

companion object {
val instance: CacheService
get() = ServiceManager.getService(CacheService::class.java)
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cn.yiiguxing.plugin.translate.trans

import cn.yiiguxing.plugin.translate.message
import cn.yiiguxing.plugin.translate.util.urlEncode
import com.google.gson.JsonSyntaxException
import com.intellij.util.io.HttpRequests
import com.intellij.util.io.RequestBuilder
Expand All @@ -16,14 +17,21 @@ import javax.net.ssl.SSLHandshakeException
*/
abstract class AbstractTranslator : Translator {

protected abstract fun getTranslateUrl(
protected abstract fun getRequestUrl(
text: String,
srcLang: Lang,
targetLang: Lang,
forDocumentation: Boolean
): String

protected open fun buildRequest(builder: RequestBuilder, orDocumentation: Boolean) {}
protected abstract fun getRequestParams(
text: String,
srcLang: Lang,
targetLang: Lang,
forDocumentation: Boolean
): List<Pair<String, String>>

protected open fun buildRequest(builder: RequestBuilder, forDocumentation: Boolean) {}

protected abstract fun parserResult(
original: String,
Expand Down Expand Up @@ -56,10 +64,15 @@ abstract class AbstractTranslator : Translator {
throw UnsupportedLanguageException(targetLang, name)
}

return HttpRequests.request(getTranslateUrl(`in`, srcLang, targetLang, forDocumentation))
val url = getRequestUrl(`in`, srcLang, targetLang, forDocumentation)
val params = getRequestParams(`in`, srcLang, targetLang, forDocumentation)
val data = params.joinToString("&") { (key, value) -> "$key=${value.urlEncode()}" }

return HttpRequests.post(url, "application/x-www-form-urlencoded")
.also { buildRequest(it, forDocumentation) }
.connect {
parserResult(`in`, srcLang, targetLang, it.readString(null), forDocumentation)
it.write(data)
parserResult(`in`, srcLang, targetLang, it.readString(), forDocumentation)
}
}

Expand Down
Loading

0 comments on commit 0d85bc0

Please sign in to comment.