feat: checkLanguage utils

This commit is contained in:
DIYgod 2025-01-14 20:51:17 +08:00
parent 2edebdfcdb
commit 225e470db8
No known key found for this signature in database
4 changed files with 61 additions and 30 deletions

View File

@ -1,9 +1,8 @@
import type { SupportedLanguages } from "@follow/models/types"
import { franc } from "franc-min"
import type { FlatEntryModel } from "~/store/entry"
import { LanguageMap, translate } from "./translate"
import { checkLanguage, translate } from "./translate"
function textNodesUnder(el: Node) {
const children: Node[] = el.nodeType === Node.TEXT_NODE ? [el] : []
@ -17,7 +16,7 @@ function textNodesUnder(el: Node) {
return children
}
const tagsToDuplicate = ["h1", "h2", "h3", "h4", "h5", "h6", "p", "li", "blockquote"]
const tagsToDuplicate = ["h1", "h2", "h3", "h4", "h5", "h6", "p", "li", "blockquote", "article"]
export function immersiveTranslate({
html,
@ -94,9 +93,14 @@ export function immersiveTranslate({
}) as HTMLElement[]
for (const tag of tags) {
const sourceLanguage = franc(tag.textContent ?? "")
if (sourceLanguage === LanguageMap[translation].code) {
return
if (tag.textContent) {
const isLanguageMatch = checkLanguage({
content: tag.textContent,
language: translation,
})
if (isLanguageMatch) {
continue
}
}
const children = Array.from(tag.childNodes)

View File

@ -1,6 +1,7 @@
import { parseHtml } from "@follow/components/ui/markdown/parse-html.js"
import { views } from "@follow/constants"
import type { SupportedLanguages } from "@follow/models/types"
import { franc } from "franc-min"
import type { FlatEntryModel } from "~/store/entry"
@ -35,6 +36,28 @@ export const LanguageMap: Record<
code: "cmn",
},
}
export const checkLanguage = ({
content,
language,
}: {
content: string
language: SupportedLanguages
}) => {
if (!content) return true
const pureContent = parseHtml(content)
.toText()
.replaceAll(/https?:\/\/\S+|www\.\S+/g, " ")
const sourceLanguage = franc(pureContent, {
only: [LanguageMap[language].code],
})
if (sourceLanguage === LanguageMap[language].code) {
return true
} else {
return false
}
}
export async function translate({
entry,
view,
@ -55,22 +78,14 @@ export async function translate({
if (extraFields) {
fields = [...fields, ...extraFields]
}
const { franc } = await import("franc-min")
fields = fields.filter((field) => {
if (language && entry.entries[field]) {
const content = parseHtml(entry.entries[field])
.toText()
.replaceAll(/https?:\/\/\S+|www\.\S+/g, " ")
const sourceLanguage = franc(content, {
only: [LanguageMap[language].code],
const isLanguageMatch = checkLanguage({
content: entry.entries[field],
language,
})
if (sourceLanguage === LanguageMap[language].code) {
return false
} else {
return true
}
return !isLanguageMatch
} else {
return false
}

View File

@ -16,7 +16,7 @@ import { ShadowDOM } from "~/components/common/ShadowDOM"
import { useInPeekModal } from "~/components/ui/modal/inspire/PeekModal"
import { useRouteParamsSelector } from "~/hooks/biz/useRouteParams"
import { useAuthQuery } from "~/hooks/common"
import { LanguageMap } from "~/lib/translate"
import { checkLanguage } from "~/lib/translate"
import { WrappedElementProvider } from "~/providers/wrapped-element-provider"
import { Queries } from "~/queries"
import { useEntry } from "~/store/entry"
@ -108,7 +108,9 @@ export const EntryContent: Component<EntryContentProps> = ({
)
const customCSS = useUISettingKey("customCSS")
const showAITranslation = useShowAITranslation()
const translationLanguage = useGeneralSettingSelector((s) => s.translationLanguage)
const translationLanguage = useGeneralSettingSelector(
(s) => s.translationLanguage,
) as SupportedLanguages
if (!entry) return null
@ -120,13 +122,17 @@ export const EntryContent: Component<EntryContentProps> = ({
const fullText = html.textContent ?? ""
if (!fullText) return
const { franc } = await import("franc-min")
const translation =
entry.settings?.translation ?? (showAITranslation ? translationLanguage : undefined)
const sourceLanguage = franc(fullText)
if (translation && sourceLanguage === LanguageMap[translation].code) {
return
if (translation) {
const isLanguageMatch = checkLanguage({
content: fullText,
language: translation,
})
if (isLanguageMatch) {
return
}
}
const { immersiveTranslate } = await import("~/lib/immersive-translate")

View File

@ -14,7 +14,7 @@ import { ShadowDOM } from "~/components/common/ShadowDOM"
import { useNavigateEntry } from "~/hooks/biz/useNavigateEntry"
import { useRouteParamsSelector } from "~/hooks/biz/useRouteParams"
import { useAuthQuery, usePreventOverscrollBounce } from "~/hooks/common"
import { LanguageMap } from "~/lib/translate"
import { checkLanguage } from "~/lib/translate"
import { WrappedElementProvider } from "~/providers/wrapped-element-provider"
import { Queries } from "~/queries"
import { useEntry } from "~/store/entry"
@ -102,7 +102,9 @@ export const EntryContent: Component<{
const [scrollElement, setScrollElement] = useState<HTMLElement | null>(null)
const showAITranslation = useShowAITranslation()
const translationLanguage = useGeneralSettingSelector((s) => s.translationLanguage)
const translationLanguage = useGeneralSettingSelector(
(s) => s.translationLanguage,
) as SupportedLanguages
if (!entry) return null
@ -114,13 +116,17 @@ export const EntryContent: Component<{
const fullText = html.textContent ?? ""
if (!fullText) return
const { franc } = await import("franc-min")
const translation =
entry.settings?.translation ?? (showAITranslation ? translationLanguage : undefined)
const sourceLanguage = franc(fullText)
if (translation && sourceLanguage === LanguageMap[translation].code) {
return
if (translation) {
const isLanguageMatch = checkLanguage({
content: fullText,
language: translation,
})
if (isLanguageMatch) {
return
}
}
const { immersiveTranslate } = await import("~/lib/immersive-translate")