diff --git a/apps/desktop/locales/settings/en.json b/apps/desktop/locales/settings/en.json index 84e0b1804..61c34c80b 100644 --- a/apps/desktop/locales/settings/en.json +++ b/apps/desktop/locales/settings/en.json @@ -187,7 +187,9 @@ "general.startup_screen.timeline": "Timeline", "general.startup_screen.title": "Startup Screen", "general.timeline": "Timeline", - "general.translation_language": "Translation Language", + "general.action_language.label": "Action Language", + "general.action_language.default": "Default (UI Language)", + "general.action_language.description": "The language used for translation and summary", "general.unread": "Unread", "general.voices": "Voices", "integration.eagle.enable.description": "Display 'Save media to Eagle' button when available.", diff --git a/apps/desktop/locales/settings/ja.json b/apps/desktop/locales/settings/ja.json index b99235938..f991c861b 100644 --- a/apps/desktop/locales/settings/ja.json +++ b/apps/desktop/locales/settings/ja.json @@ -167,7 +167,6 @@ "general.startup_screen.timeline": "タイムライン", "general.startup_screen.title": "スタートアップスクリーン", "general.timeline": "タイムライン", - "general.translation_language": "翻訳する言語", "general.unread": "未読", "general.voices": "音声", "integration.eagle.enable.description": "利用可能な場合、'Eagle にメディアを保存' ボタンを表示します。", diff --git a/apps/desktop/locales/settings/ko.json b/apps/desktop/locales/settings/ko.json index 8a5fa4e47..a216d3a77 100644 --- a/apps/desktop/locales/settings/ko.json +++ b/apps/desktop/locales/settings/ko.json @@ -172,7 +172,6 @@ "general.startup_screen.timeline": "타임라인", "general.startup_screen.title": "시작 화면", "general.timeline": "타임라인", - "general.translation_language": "번역 언어", "general.unread": "읽지 않음", "general.voices": "음성", "integration.eagle.enable.description": "가능할 때 '미디어를 Eagle 에 저장' 버튼 표시.", diff --git a/apps/desktop/locales/settings/zh-CN.json b/apps/desktop/locales/settings/zh-CN.json index 2f2dde372..879eb8f30 100644 --- a/apps/desktop/locales/settings/zh-CN.json +++ b/apps/desktop/locales/settings/zh-CN.json @@ -187,7 +187,6 @@ "general.startup_screen.timeline": "时间线", "general.startup_screen.title": "起始界面", "general.timeline": "时间线", - "general.translation_language": "翻译语言", "general.unread": "未读", "general.voices": "声音", "integration.eagle.enable.description": "显示「保存到 Eagle」按钮(如果可用)。", diff --git a/apps/desktop/locales/settings/zh-HK.json b/apps/desktop/locales/settings/zh-HK.json index db13205a2..5874d3472 100644 --- a/apps/desktop/locales/settings/zh-HK.json +++ b/apps/desktop/locales/settings/zh-HK.json @@ -187,7 +187,6 @@ "general.startup_screen.timeline": "時間軸", "general.startup_screen.title": "啟動畫面", "general.timeline": "時間軸", - "general.translation_language": "翻譯語言", "general.unread": "未讀", "general.voices": "語音", "integration.eagle.enable.description": "顯示「將媒體儲存到 Eagle」按鈕(如果可用)", diff --git a/apps/desktop/locales/settings/zh-TW.json b/apps/desktop/locales/settings/zh-TW.json index dead3bd5e..e348ac5e6 100644 --- a/apps/desktop/locales/settings/zh-TW.json +++ b/apps/desktop/locales/settings/zh-TW.json @@ -172,7 +172,6 @@ "general.startup_screen.timeline": "時間軸", "general.startup_screen.title": "開始畫面", "general.timeline": "時間軸", - "general.translation_language": "翻譯語言", "general.unread": "未讀", "general.voices": "聲音", "integration.eagle.enable.description": "顯示「將媒體儲存到 Eagle」按鈕(如果可用)。", diff --git a/apps/desktop/src/renderer/src/atoms/settings/general.ts b/apps/desktop/src/renderer/src/atoms/settings/general.ts index ca78f0258..f4a28a9e8 100644 --- a/apps/desktop/src/renderer/src/atoms/settings/general.ts +++ b/apps/desktop/src/renderer/src/atoms/settings/general.ts @@ -1,13 +1,16 @@ import { createSettingAtom } from "@follow/atoms/helper/setting.js" +import type { SupportedLanguages } from "@follow/models" import type { GeneralSettings } from "@follow/shared/interface/settings" import { jotaiStore } from "~/lib/jotai" +export const DEFAULT_ACTION_LANGUAGE = "default" + const createDefaultSettings = (): GeneralSettings => ({ // App appLaunchOnStartup: false, language: "en", - translationLanguage: "zh-CN", + actionLanguage: DEFAULT_ACTION_LANGUAGE, // mobile app startupScreen: "timeline", @@ -47,6 +50,14 @@ export const { settingAtom: __generalSettingAtom, } = createSettingAtom("general", createDefaultSettings) +export function useActionLanguage() { + const actionLanguage = useGeneralSettingSelector((s) => s.actionLanguage) + const language = useGeneralSettingSelector((s) => s.language) + return ( + actionLanguage === DEFAULT_ACTION_LANGUAGE ? language : actionLanguage + ) as SupportedLanguages +} + export const subscribeShouldUseIndexedDB = (callback: (value: boolean) => void) => jotaiStore.sub(__generalSettingAtom, () => callback(getGeneralSettings().dataPersist)) diff --git a/apps/desktop/src/renderer/src/lib/immersive-translate.ts b/apps/desktop/src/renderer/src/lib/immersive-translate.ts index 772b8019e..6665ed9e7 100644 --- a/apps/desktop/src/renderer/src/lib/immersive-translate.ts +++ b/apps/desktop/src/renderer/src/lib/immersive-translate.ts @@ -36,11 +36,9 @@ export function immersiveTranslate({ return } - const translation = entry.settings?.translation ?? targetLanguage - const immersiveTranslateMark = html.querySelectorAll("[data-immersive-translate-mark=true]") if (immersiveTranslateMark.length > 0) { - if (translation) { + if (targetLanguage) { return } @@ -49,7 +47,7 @@ export function immersiveTranslate({ } } - if (!translation) { + if (!targetLanguage) { return } @@ -61,7 +59,7 @@ export function immersiveTranslate({ translate({ entry, - language: translation, + language: targetLanguage, part: textNode.textContent, extraFields: ["content"], }).then((transformed) => { @@ -96,7 +94,7 @@ export function immersiveTranslate({ if (tag.textContent) { const isLanguageMatch = checkLanguage({ content: tag.textContent, - language: translation, + language: targetLanguage, }) if (isLanguageMatch) { continue @@ -151,7 +149,7 @@ export function immersiveTranslate({ translate({ entry, - language: translation, + language: targetLanguage, part: textContent, extraFields: ["content"], }).then((transformed) => { diff --git a/apps/desktop/src/renderer/src/lib/translate.ts b/apps/desktop/src/renderer/src/lib/translate.ts index bb303b4ec..93aefdaed 100644 --- a/apps/desktop/src/renderer/src/lib/translate.ts +++ b/apps/desktop/src/renderer/src/lib/translate.ts @@ -1,42 +1,13 @@ import { parseHtml } from "@follow/components/ui/markdown/parse-html.js" import { views } from "@follow/constants" import type { SupportedLanguages } from "@follow/models/types" +import { LANGUAGE_MAP } from "@follow/shared" import { franc } from "franc-min" import type { FlatEntryModel } from "~/store/entry" import { apiClient } from "./api-fetch" -export const LanguageMap: Record< - SupportedLanguages, - { - label: string - value: string - code: string - } -> = { - en: { - value: "en", - label: "English", - code: "eng", - }, - ja: { - value: "ja", - label: "Japanese", - code: "jpn", - }, - "zh-CN": { - value: "zh-CN", - label: "Simplified Chinese", - code: "cmn", - }, - "zh-TW": { - value: "zh-TW", - label: "Traditional Chinese (Taiwan)", - code: "cmn", - }, -} - export const checkLanguage = ({ content, language, @@ -48,10 +19,12 @@ export const checkLanguage = ({ const pureContent = parseHtml(content) .toText() .replaceAll(/https?:\/\/\S+|www\.\S+/g, " ") + const { code } = LANGUAGE_MAP[language] + if (!code) return false const sourceLanguage = franc(pureContent, { - only: [LanguageMap[language].code], + only: [code], }) - if (sourceLanguage === LanguageMap[language].code) { + if (sourceLanguage === code) { return true } else { return false diff --git a/apps/desktop/src/renderer/src/modules/action/target-action-list.tsx b/apps/desktop/src/renderer/src/modules/action/target-action-list.tsx index c4243c905..196254619 100644 --- a/apps/desktop/src/renderer/src/modules/action/target-action-list.tsx +++ b/apps/desktop/src/renderer/src/modules/action/target-action-list.tsx @@ -1,7 +1,6 @@ import { ActionButton, Button } from "@follow/components/ui/button/index.js" import { Divider } from "@follow/components/ui/divider/index.js" import { Input } from "@follow/components/ui/input/index.js" -import { ResponsiveSelect } from "@follow/components/ui/select/responsive.js" import { Table, TableBody, @@ -10,7 +9,7 @@ import { TableHeader, TableRow, } from "@follow/components/ui/table/index.jsx" -import type { ActionModel, SupportedLanguages } from "@follow/models/types" +import type { ActionModel } from "@follow/models/types" import { Fragment, useMemo } from "react" import { useTranslation } from "react-i18next" @@ -31,28 +30,6 @@ type Action = { onRemove: (data: ActionModel) => void } -const TransitionOptions: { - label: string - value: SupportedLanguages -}[] = [ - { - label: "English", - value: "en", - }, - { - label: "日本語", - value: "ja", - }, - { - label: "简体中文", - value: "zh-CN", - }, - { - label: "繁體中文", - value: "zh-TW", - }, -] - const AddTableRow = ({ onClick, disabled }: { onClick?: () => void; disabled?: boolean }) => { const { t } = useTranslation("settings") return ( @@ -108,26 +85,11 @@ export const TargetActionList = ({ index }: { index: number }) => { title: t("actions.action_card.translate_into"), enabled: !!translation, onInit: (data) => { - data.result.translation = "zh-CN" + data.result.translation = true }, onRemove: (data) => { delete data.result.translation }, - config: () => ( - { - onChange((data) => { - data.result.translation = value - }) - }} - items={TransitionOptions} - triggerClassName="w-fit max-w-44 text-sm" - /> - ), - configInline: true, }, { title: t("actions.action_card.enable_readability"), diff --git a/apps/desktop/src/renderer/src/modules/entry-column/Items/picture-masonry.tsx b/apps/desktop/src/renderer/src/modules/entry-column/Items/picture-masonry.tsx index bd42c1020..2ddaaf46b 100644 --- a/apps/desktop/src/renderer/src/modules/entry-column/Items/picture-masonry.tsx +++ b/apps/desktop/src/renderer/src/modules/entry-column/Items/picture-masonry.tsx @@ -27,7 +27,7 @@ import { } from "react" import { useEventCallback } from "usehooks-ts" -import { useGeneralSettingKey } from "~/atoms/settings/general" +import { useActionLanguage, useGeneralSettingKey } from "~/atoms/settings/general" import { MediaContainerWidthProvider } from "~/components/ui/media" import { useAuthQuery } from "~/hooks/common/useBizQuery" import { Queries } from "~/queries" @@ -248,11 +248,12 @@ const MasonryRender: React.ComponentType< > = ({ data, index }) => { const firstScreenReady = useContext(FirstScreenReadyContext) const entry = useEntry(data.entryId) + const actionLanguage = useActionLanguage() const translation = useAuthQuery( Queries.ai.translation({ entry: entry!, view: entry?.view, - language: entry?.settings?.translation, + language: actionLanguage, }), { enabled: !!entry?.settings?.translation, diff --git a/apps/desktop/src/renderer/src/modules/entry-column/item.tsx b/apps/desktop/src/renderer/src/modules/entry-column/item.tsx index 94d3fd6b2..9596d64e4 100644 --- a/apps/desktop/src/renderer/src/modules/entry-column/item.tsx +++ b/apps/desktop/src/renderer/src/modules/entry-column/item.tsx @@ -5,6 +5,7 @@ import { cn } from "@follow/utils/utils" import type { FC } from "react" import { memo } from "react" +import { useActionLanguage } from "~/atoms/settings/general" import { useAuthQuery } from "~/hooks/common" import { Queries } from "~/queries" import type { FlatEntryModel } from "~/store/entry" @@ -20,11 +21,12 @@ interface EntryItemProps { view?: number } function EntryItemImpl({ entry, view }: { entry: FlatEntryModel; view?: number }) { + const actionLanguage = useActionLanguage() const translation = useAuthQuery( Queries.ai.translation({ entry, view, - language: entry.settings?.translation, + language: actionLanguage, }), { enabled: !!entry.settings?.translation, diff --git a/apps/desktop/src/renderer/src/modules/entry-content/components/EntryTitle.tsx b/apps/desktop/src/renderer/src/modules/entry-content/components/EntryTitle.tsx index 772f776eb..e6f604a99 100644 --- a/apps/desktop/src/renderer/src/modules/entry-content/components/EntryTitle.tsx +++ b/apps/desktop/src/renderer/src/modules/entry-content/components/EntryTitle.tsx @@ -1,10 +1,9 @@ -import type { SupportedLanguages } from "@follow/models/types" import { cn } from "@follow/utils/utils" import dayjs from "dayjs" import { useMemo } from "react" import { useShowAITranslation } from "~/atoms/ai-translation" -import { useGeneralSettingSelector } from "~/atoms/settings/general" +import { useActionLanguage } from "~/atoms/settings/general" import { useUISettingKey } from "~/atoms/settings/ui" import { useWhoami } from "~/atoms/user" import { RelativeTime } from "~/components/ui/datetime" @@ -49,12 +48,12 @@ export const EntryTitle = ({ entryId, compact }: EntryLinkProps) => { }, [entry?.entries.authorUrl, entry?.entries.url, feed?.siteUrl, feed?.type, inbox]) const showAITranslation = useShowAITranslation() || !!entry?.settings?.translation - const translationLanguage = useGeneralSettingSelector((s) => s.translationLanguage) + const actionLanguage = useActionLanguage() const translation = useAuthQuery( Queries.ai.translation({ entry: entry!, - language: entry?.settings?.translation || (translationLanguage as SupportedLanguages), + language: actionLanguage, extraFields: ["title"], }), { diff --git a/apps/desktop/src/renderer/src/modules/entry-content/index.electron.tsx b/apps/desktop/src/renderer/src/modules/entry-content/index.electron.tsx index 842746196..d9dc12eeb 100644 --- a/apps/desktop/src/renderer/src/modules/entry-content/index.electron.tsx +++ b/apps/desktop/src/renderer/src/modules/entry-content/index.electron.tsx @@ -1,7 +1,7 @@ import { MemoedDangerousHTMLStyle } from "@follow/components/common/MemoedDangerousHTMLStyle.js" import { ScrollArea } from "@follow/components/ui/scroll-area/index.js" import { useTitle } from "@follow/hooks" -import type { FeedModel, InboxModel, SupportedLanguages } from "@follow/models/types" +import type { FeedModel, InboxModel } from "@follow/models/types" import { IN_ELECTRON } from "@follow/shared/constants" import { stopPropagation } from "@follow/utils/dom" import { cn } from "@follow/utils/utils" @@ -11,7 +11,7 @@ import { useEffect, useMemo, useRef } from "react" import { useShowAITranslation } from "~/atoms/ai-translation" import { useEntryIsInReadability } from "~/atoms/readability" -import { useGeneralSettingSelector } from "~/atoms/settings/general" +import { useActionLanguage } from "~/atoms/settings/general" import { useUISettingKey } from "~/atoms/settings/ui" import { ShadowDOM } from "~/components/common/ShadowDOM" import { useInPeekModal } from "~/components/ui/modal/inspire/PeekModal" @@ -117,9 +117,7 @@ export const EntryContent: Component = ({ ) const customCSS = useUISettingKey("customCSS") const showAITranslation = useShowAITranslation() - const translationLanguage = useGeneralSettingSelector( - (s) => s.translationLanguage, - ) as SupportedLanguages + const actionLanguage = useActionLanguage() if (!entry) return null @@ -131,8 +129,7 @@ export const EntryContent: Component = ({ const fullText = html.textContent ?? "" if (!fullText) return - const translation = - entry.settings?.translation ?? (showAITranslation ? translationLanguage : undefined) + const translation = showAITranslation ? actionLanguage : undefined if (translation) { const isLanguageMatch = checkLanguage({ @@ -148,7 +145,7 @@ export const EntryContent: Component = ({ immersiveTranslate({ html, entry, - targetLanguage: translation as SupportedLanguages, + targetLanguage: translation, cache: { get: (key: string) => getTranslationCache()[key], set: (key: string, value: string) => diff --git a/apps/desktop/src/renderer/src/modules/entry-content/index.mobile.tsx b/apps/desktop/src/renderer/src/modules/entry-content/index.mobile.tsx index 013fefcf0..88be73b4d 100644 --- a/apps/desktop/src/renderer/src/modules/entry-content/index.mobile.tsx +++ b/apps/desktop/src/renderer/src/modules/entry-content/index.mobile.tsx @@ -1,7 +1,7 @@ import { MemoedDangerousHTMLStyle } from "@follow/components/common/MemoedDangerousHTMLStyle.js" import { ScrollElementContext } from "@follow/components/ui/scroll-area/ctx.js" import { useTitle } from "@follow/hooks" -import type { FeedModel, InboxModel, SupportedLanguages } from "@follow/models/types" +import type { FeedModel, InboxModel } from "@follow/models/types" import { nextFrame, stopPropagation } from "@follow/utils/dom" import { cn } from "@follow/utils/utils" import { ErrorBoundary } from "@sentry/react" @@ -9,7 +9,7 @@ import { useEffect, useMemo, useState } from "react" import { useShowAITranslation } from "~/atoms/ai-translation" import { useAudioPlayerAtomSelector } from "~/atoms/player" -import { useGeneralSettingSelector } from "~/atoms/settings/general" +import { useActionLanguage } from "~/atoms/settings/general" import { useUISettingKey } from "~/atoms/settings/ui" import { ShadowDOM } from "~/components/common/ShadowDOM" import { useNavigateEntry } from "~/hooks/biz/useNavigateEntry" @@ -104,9 +104,7 @@ export const EntryContent: Component<{ const customCSS = useUISettingKey("customCSS") const showAITranslation = useShowAITranslation() - const translationLanguage = useGeneralSettingSelector( - (s) => s.translationLanguage, - ) as SupportedLanguages + const actionLanguage = useActionLanguage() const contentLineHeight = useUISettingKey("contentLineHeight") const contentFontSize = useUISettingKey("contentFontSize") @@ -134,8 +132,7 @@ export const EntryContent: Component<{ const fullText = html.textContent ?? "" if (!fullText) return - const translation = - entry.settings?.translation ?? (showAITranslation ? translationLanguage : undefined) + const translation = showAITranslation ? actionLanguage : undefined if (translation) { const isLanguageMatch = checkLanguage({ @@ -151,7 +148,7 @@ export const EntryContent: Component<{ immersiveTranslate({ html, entry, - targetLanguage: translation as SupportedLanguages, + targetLanguage: translation, cache: { get: (key: string) => getTranslationCache()[key], set: (key: string, value: string) => diff --git a/apps/desktop/src/renderer/src/modules/entry-content/index.shared.tsx b/apps/desktop/src/renderer/src/modules/entry-content/index.shared.tsx index 9ad0a39a8..13b56ccce 100644 --- a/apps/desktop/src/renderer/src/modules/entry-content/index.shared.tsx +++ b/apps/desktop/src/renderer/src/modules/entry-content/index.shared.tsx @@ -21,6 +21,7 @@ import { useEntryInReadabilityStatus, useEntryReadabilityContent, } from "~/atoms/readability" +import { useActionLanguage } from "~/atoms/settings/general" import { enableShowSourceContent } from "~/atoms/source-content" import { CopyButton } from "~/components/ui/button/CopyButton" import { Toc } from "~/components/ui/markdown/components/Toc" @@ -319,10 +320,11 @@ export function AISummary({ entryId }: { entryId: string }) { const { t } = useTranslation() const entry = useEntry(entryId) const showAISummary = useShowAISummary() || !!entry?.settings?.summary + const actionLanguage = useActionLanguage() const summary = useAuthQuery( Queries.ai.summary({ entryId, - language: entry?.settings?.translation, + language: actionLanguage, }), { enabled: showAISummary, diff --git a/apps/desktop/src/renderer/src/modules/settings/tabs/general.tsx b/apps/desktop/src/renderer/src/modules/settings/tabs/general.tsx index 4c1018355..7e3394b65 100644 --- a/apps/desktop/src/renderer/src/modules/settings/tabs/general.tsx +++ b/apps/desktop/src/renderer/src/modules/settings/tabs/general.tsx @@ -1,6 +1,7 @@ import { useMobile } from "@follow/components/hooks/useMobile.js" import { ResponsiveSelect } from "@follow/components/ui/select/responsive.js" import { useTypeScriptHappyCallback } from "@follow/hooks" +import { LANGUAGE_MAP } from "@follow/shared" import { IN_ELECTRON } from "@follow/shared/constants" import { cn } from "@follow/utils/utils" import { useQuery } from "@tanstack/react-query" @@ -13,6 +14,7 @@ import { currentSupportedLanguages } from "~/@types/constants" import { defaultResources } from "~/@types/default-resource" import { langLoadingLockMapAtom } from "~/atoms/lang" import { + DEFAULT_ACTION_LANGUAGE, setGeneralSetting, useGeneralSettingKey, useGeneralSettingSelector, @@ -22,7 +24,6 @@ import { useProxyValue, useSetProxy } from "~/hooks/biz/useProxySetting" import { useMinimizeToTrayValue, useSetMinimizeToTray } from "~/hooks/biz/useTraySetting" import { fallbackLanguage } from "~/i18n" import { tipcClient } from "~/lib/client" -import { LanguageMap } from "~/lib/translate" import { setTranslationCache } from "~/modules/entry-content/atoms" import { SettingDescription, SettingInput, SettingSwitch } from "../control" @@ -68,7 +69,7 @@ export const SettingGeneral = () => { IN_ELECTRON && MinimizeToTraySetting, isMobile && StartupScreenSelector, LanguageSelector, - TranslateLanguageSelector, + ActionLanguageSelector, { type: "title", @@ -243,23 +244,31 @@ export const LanguageSelector = ({ ) } -const TranslateLanguageSelector = () => { +const ActionLanguageSelector = () => { const { t } = useTranslation("settings") - const translationLanguage = useGeneralSettingKey("translationLanguage") + const actionLanguage = useGeneralSettingKey("actionLanguage") return (
- {t("general.translation_language")} +
+ {t("general.action_language.label")} + + {t("general.action_language.description")} + +
{ - setGeneralSetting("translationLanguage", value) + setGeneralSetting("actionLanguage", value) setTranslationCache({}) }} - items={Object.values(LanguageMap)} + items={[ + { label: t("general.action_language.default"), value: DEFAULT_ACTION_LANGUAGE }, + ...Object.values(LANGUAGE_MAP), + ]} />
) diff --git a/apps/mobile/src/atoms/settings/general.ts b/apps/mobile/src/atoms/settings/general.ts index f9a903b03..4d7bc5681 100644 --- a/apps/mobile/src/atoms/settings/general.ts +++ b/apps/mobile/src/atoms/settings/general.ts @@ -6,7 +6,7 @@ const createDefaultSettings = (): GeneralSettings => ({ // App language: "en", - translationLanguage: "zh-CN", + actionLanguage: "zh-CN", // Data control diff --git a/apps/mobile/src/interfaces/settings/general.ts b/apps/mobile/src/interfaces/settings/general.ts index 5948d6ef3..78c1ac969 100644 --- a/apps/mobile/src/interfaces/settings/general.ts +++ b/apps/mobile/src/interfaces/settings/general.ts @@ -1,6 +1,6 @@ export interface GeneralSettings { language: string - translationLanguage: string + actionLanguage: string sendAnonymousData: boolean unreadOnly: boolean diff --git a/apps/mobile/src/lib/language.ts b/apps/mobile/src/lib/language.ts index cbcf4e61a..d1278617f 100644 --- a/apps/mobile/src/lib/language.ts +++ b/apps/mobile/src/lib/language.ts @@ -2,32 +2,3 @@ import type { languageSchema } from "@follow/shared/src/hono" import type { z } from "zod" export type SupportedLanguages = z.infer -export const LanguageMap: Record< - SupportedLanguages, - { - label: string - value: string - code: string - } -> = { - en: { - value: "en", - label: "English", - code: "eng", - }, - ja: { - value: "ja", - label: "Japanese", - code: "jpn", - }, - "zh-CN": { - value: "zh-CN", - label: "Simplified Chinese", - code: "cmn", - }, - "zh-TW": { - value: "zh-TW", - label: "Traditional Chinese (Taiwan)", - code: "cmn", - }, -} diff --git a/apps/mobile/src/modules/settings/actions/components.tsx b/apps/mobile/src/modules/settings/actions/components.tsx deleted file mode 100644 index 2f1a0f29b..000000000 --- a/apps/mobile/src/modules/settings/actions/components.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { Select } from "@/src/components/ui/form/Select" -import { GroupedInsetListCell } from "@/src/components/ui/grouped/GroupedList" -import { actionActions } from "@/src/store/action/store" -import type { ActionRule } from "@/src/store/action/types" - -import { translationOptions } from "./constant" - -export const ActionFormTranslation: React.FC<{ rule: ActionRule }> = ({ rule }) => { - const currentTranslation = translationOptions.find( - (translation) => translation.value === rule.result?.translation, - ) - return ( - - { - setGeneralSetting("translationLanguage", value) + setGeneralSetting("actionLanguage", value) }} - options={Object.values(LanguageMap)} + options={Object.values(LANGUAGE_MAP)} /> diff --git a/apps/mobile/src/store/summary/store.ts b/apps/mobile/src/store/summary/store.ts index 7beedb90c..22b7ca5e8 100644 --- a/apps/mobile/src/store/summary/store.ts +++ b/apps/mobile/src/store/summary/store.ts @@ -1,3 +1,4 @@ +import { getGeneralSettings } from "@/src/atoms/settings/general" import type { SummarySchema } from "@/src/database/schemas/types" import { apiClient } from "@/src/lib/api-fetch" import { summaryService } from "@/src/services/summary" @@ -103,14 +104,14 @@ class SummarySyncService { state.generatingStatus[entryId] = SummaryGeneratingStatus.Pending }) - const language = entry.settings?.translation + const { actionLanguage } = getGeneralSettings() + // Use Our AI to generate summary const summary = await apiClient.ai.summary .$get({ query: { id: entryId, - - language, + language: actionLanguage as any, }, }) .then((summary) => { @@ -121,7 +122,7 @@ class SummarySyncService { } state.data[entryId] = { - lang: language, + lang: actionLanguage, summary: summary.data, lastAccessed: Date.now(), } @@ -142,7 +143,7 @@ class SummarySyncService { { entryId, summary, - language: language ?? null, + language: actionLanguage ?? null, }, ]) } diff --git a/packages/models/src/types.ts b/packages/models/src/types.ts index 80e65451c..4ee8ed054 100644 --- a/packages/models/src/types.ts +++ b/packages/models/src/types.ts @@ -125,7 +125,7 @@ export type ActionModel = { }[][] result: { disabled?: boolean - translation?: string + translation?: boolean | string summary?: boolean readability?: boolean silence?: boolean diff --git a/packages/shared/exports.ts b/packages/shared/exports.ts index 5e57c2265..eabd94dfb 100644 --- a/packages/shared/exports.ts +++ b/packages/shared/exports.ts @@ -1,3 +1,4 @@ export * from "./src/bridge" export * from "./src/env" export { type AppType } from "./src/hono" +export * from "./src/language" diff --git a/packages/shared/src/hono.ts b/packages/shared/src/hono.ts index 58a852a64..9a145de76 100644 --- a/packages/shared/src/hono.ts +++ b/packages/shared/src/hono.ts @@ -359,7 +359,7 @@ declare const achievementsOpenAPISchema: zod.ZodObject<{ tx: string | null; }>; -declare const languageSchema: z.ZodEnum<["en", "ja", "zh-CN", "zh-TW"]>; +declare const languageSchema: z.ZodEnum<["ar-DZ", "ar-IQ", "ar-KW", "ar-MA", "ar-SA", "ar-TN", "de", "en", "es", "fi", "fr", "it", "ja", "ko", "pt", "ru", "tr", "zh-CN", "zh-HK", "zh-TW"]>; declare const ruleFieldSchema: z.ZodEnum<["all", "title", "content", "author", "url", "order"]>; declare const ruleOperatorSchema: z.ZodEnum<["contains", "not_contains", "eq", "not_eq", "gt", "lt", "regex"]>; declare const conditionItemSchema: z.ZodObject<{ @@ -407,7 +407,7 @@ declare const actions: drizzle_orm_pg_core.PgTableWithColumns<{ condition: ConditionItem[] | ConditionItem[][]; result: { disabled?: boolean; - translation?: z.infer; + translation?: z.infer | boolean; summary?: boolean; readability?: boolean; sourceContent?: boolean; @@ -442,7 +442,7 @@ declare const actions: drizzle_orm_pg_core.PgTableWithColumns<{ condition: ConditionItem[] | ConditionItem[][]; result: { disabled?: boolean; - translation?: z.infer; + translation?: z.infer | boolean; summary?: boolean; readability?: boolean; sourceContent?: boolean; @@ -494,7 +494,7 @@ declare const actionsItemOpenAPISchema: z.ZodObject<{ }>, "many">, "many">]>; result: z.ZodObject<{ disabled: z.ZodOptional; - translation: z.ZodOptional>; + translation: z.ZodOptional, z.ZodBoolean]>>; summary: z.ZodOptional; readability: z.ZodOptional; sourceContent: z.ZodOptional; @@ -527,7 +527,7 @@ declare const actionsItemOpenAPISchema: z.ZodObject<{ webhooks: z.ZodOptional>; }, "strip", z.ZodTypeAny, { disabled?: boolean | undefined; - translation?: "en" | "ja" | "zh-CN" | "zh-TW" | undefined; + translation?: boolean | "ar-DZ" | "ar-IQ" | "ar-KW" | "ar-MA" | "ar-SA" | "ar-TN" | "de" | "en" | "es" | "fi" | "fr" | "it" | "ja" | "ko" | "pt" | "ru" | "tr" | "zh-CN" | "zh-HK" | "zh-TW" | undefined; summary?: boolean | undefined; readability?: boolean | undefined; sourceContent?: boolean | undefined; @@ -546,7 +546,7 @@ declare const actionsItemOpenAPISchema: z.ZodObject<{ webhooks?: string[] | undefined; }, { disabled?: boolean | undefined; - translation?: "en" | "ja" | "zh-CN" | "zh-TW" | undefined; + translation?: boolean | "ar-DZ" | "ar-IQ" | "ar-KW" | "ar-MA" | "ar-SA" | "ar-TN" | "de" | "en" | "es" | "fi" | "fr" | "it" | "ja" | "ko" | "pt" | "ru" | "tr" | "zh-CN" | "zh-HK" | "zh-TW" | undefined; summary?: boolean | undefined; readability?: boolean | undefined; sourceContent?: boolean | undefined; @@ -577,7 +577,7 @@ declare const actionsItemOpenAPISchema: z.ZodObject<{ }[][]; result: { disabled?: boolean | undefined; - translation?: "en" | "ja" | "zh-CN" | "zh-TW" | undefined; + translation?: boolean | "ar-DZ" | "ar-IQ" | "ar-KW" | "ar-MA" | "ar-SA" | "ar-TN" | "de" | "en" | "es" | "fi" | "fr" | "it" | "ja" | "ko" | "pt" | "ru" | "tr" | "zh-CN" | "zh-HK" | "zh-TW" | undefined; summary?: boolean | undefined; readability?: boolean | undefined; sourceContent?: boolean | undefined; @@ -608,7 +608,7 @@ declare const actionsItemOpenAPISchema: z.ZodObject<{ }[][]; result: { disabled?: boolean | undefined; - translation?: "en" | "ja" | "zh-CN" | "zh-TW" | undefined; + translation?: boolean | "ar-DZ" | "ar-IQ" | "ar-KW" | "ar-MA" | "ar-SA" | "ar-TN" | "de" | "en" | "es" | "fi" | "fr" | "it" | "ja" | "ko" | "pt" | "ru" | "tr" | "zh-CN" | "zh-HK" | "zh-TW" | undefined; summary?: boolean | undefined; readability?: boolean | undefined; sourceContent?: boolean | undefined; @@ -708,7 +708,7 @@ declare const actionsOpenAPISchema: z.ZodObject, "many">, "many">]>; result: z.ZodObject<{ disabled: z.ZodOptional; - translation: z.ZodOptional>; + translation: z.ZodOptional, z.ZodBoolean]>>; summary: z.ZodOptional; readability: z.ZodOptional; sourceContent: z.ZodOptional; @@ -741,7 +741,7 @@ declare const actionsOpenAPISchema: z.ZodObject>; }, "strip", z.ZodTypeAny, { disabled?: boolean | undefined; - translation?: "en" | "ja" | "zh-CN" | "zh-TW" | undefined; + translation?: boolean | "ar-DZ" | "ar-IQ" | "ar-KW" | "ar-MA" | "ar-SA" | "ar-TN" | "de" | "en" | "es" | "fi" | "fr" | "it" | "ja" | "ko" | "pt" | "ru" | "tr" | "zh-CN" | "zh-HK" | "zh-TW" | undefined; summary?: boolean | undefined; readability?: boolean | undefined; sourceContent?: boolean | undefined; @@ -760,7 +760,7 @@ declare const actionsOpenAPISchema: z.ZodObject; newUserCallbackURL: zod.ZodOptional; errorCallbackURL: zod.ZodOptional; - provider: zod.ZodEnum<["github", ...("apple" | "discord" | "facebook" | "github" | "google" | "microsoft" | "spotify" | "twitch" | "twitter" | "dropbox" | "linkedin" | "gitlab" | "tiktok" | "reddit" | "roblox" | "vk")[]]>; + provider: zod.ZodEnum<["github", ...("apple" | "discord" | "facebook" | "github" | "google" | "microsoft" | "spotify" | "twitch" | "twitter" | "dropbox" | "linkedin" | "gitlab" | "tiktok" | "reddit" | "roblox" | "vk" | "kick")[]]>; disableRedirect: zod.ZodOptional; idToken: zod.ZodOptional>; requestSignUp: zod.ZodOptional; }, "strip", zod.ZodTypeAny, { - provider: "apple" | "discord" | "facebook" | "github" | "google" | "microsoft" | "spotify" | "twitch" | "twitter" | "dropbox" | "linkedin" | "gitlab" | "tiktok" | "reddit" | "roblox" | "vk"; + provider: "apple" | "discord" | "facebook" | "github" | "google" | "microsoft" | "spotify" | "twitch" | "twitter" | "dropbox" | "linkedin" | "gitlab" | "tiktok" | "reddit" | "roblox" | "vk" | "kick"; scopes?: string[] | undefined; idToken?: { token: string; @@ -7342,7 +7342,7 @@ declare const auth: { newUserCallbackURL?: string | undefined; disableRedirect?: boolean | undefined; }, { - provider: "apple" | "discord" | "facebook" | "github" | "google" | "microsoft" | "spotify" | "twitch" | "twitter" | "dropbox" | "linkedin" | "gitlab" | "tiktok" | "reddit" | "roblox" | "vk"; + provider: "apple" | "discord" | "facebook" | "github" | "google" | "microsoft" | "spotify" | "twitch" | "twitter" | "dropbox" | "linkedin" | "gitlab" | "tiktok" | "reddit" | "roblox" | "vk" | "kick"; scopes?: string[] | undefined; idToken?: { token: string; @@ -9244,7 +9244,7 @@ declare const auth: { linkSocialAccount: { ; - provider: zod.ZodEnum<["github", ...("apple" | "discord" | "facebook" | "github" | "google" | "microsoft" | "spotify" | "twitch" | "twitter" | "dropbox" | "linkedin" | "gitlab" | "tiktok" | "reddit" | "roblox" | "vk")[]]>; + provider: zod.ZodEnum<["github", ...("apple" | "discord" | "facebook" | "github" | "google" | "microsoft" | "spotify" | "twitch" | "twitter" | "dropbox" | "linkedin" | "gitlab" | "tiktok" | "reddit" | "roblox" | "vk" | "kick")[]]>; }, "strip", zod.ZodTypeAny, { - provider: "apple" | "discord" | "facebook" | "github" | "google" | "microsoft" | "spotify" | "twitch" | "twitter" | "dropbox" | "linkedin" | "gitlab" | "tiktok" | "reddit" | "roblox" | "vk"; + provider: "apple" | "discord" | "facebook" | "github" | "google" | "microsoft" | "spotify" | "twitch" | "twitter" | "dropbox" | "linkedin" | "gitlab" | "tiktok" | "reddit" | "roblox" | "vk" | "kick"; callbackURL?: string | undefined; }, { - provider: "apple" | "discord" | "facebook" | "github" | "google" | "microsoft" | "spotify" | "twitch" | "twitter" | "dropbox" | "linkedin" | "gitlab" | "tiktok" | "reddit" | "roblox" | "vk"; + provider: "apple" | "discord" | "facebook" | "github" | "google" | "microsoft" | "spotify" | "twitch" | "twitter" | "dropbox" | "linkedin" | "gitlab" | "tiktok" | "reddit" | "roblox" | "vk" | "kick"; callbackURL?: string | undefined; }>; use: ((inputContext: { @@ -9431,6 +9431,21 @@ declare const auth: { provider: { type: string; }; + createdAt: { + type: string; + }; + updatedAt: { + type: string; + }; + accountId: { + type: string; + }; + scopes: { + type: string; + items: { + type: string; + }; + }; }; }; }; @@ -9504,6 +9519,7 @@ declare const auth: { | undefined; @@ -9530,10 +9546,13 @@ declare const auth: { method: "POST"; body: zod.ZodObject<{ providerId: zod.ZodString; + accountId: zod.ZodString; }, "strip", zod.ZodTypeAny, { providerId: string; + accountId: string; }, { providerId: string; + accountId: string; }>; use: ((inputContext: { body?: any; @@ -12918,7 +12937,7 @@ declare const _routes: hono_hono_base.HonoBase, + { + label: string + value: string + code?: string + } +> = + /// keep-sorted + { + "ar-DZ": { + label: "Arabic (Algeria)", + value: "ar-DZ", + }, + "ar-IQ": { + label: "Arabic (Iraq)", + value: "ar-IQ", + }, + "ar-KW": { + label: "Arabic (Kuwait)", + value: "ar-KW", + }, + "ar-MA": { + label: "Arabic (Morocco)", + value: "ar-MA", + }, + "ar-SA": { + label: "Arabic (Saudi Arabia)", + value: "ar-SA", + }, + "ar-TN": { + label: "Arabic (Tunisia)", + value: "ar-TN", + }, + "zh-CN": { + label: "Simplified Chinese", + value: "zh-CN", + code: "cmn", + }, + "zh-HK": { + label: "Traditional Chinese (Hong Kong)", + value: "zh-HK", + }, + "zh-TW": { + label: "Traditional Chinese (Taiwan)", + value: "zh-TW", + }, + de: { + label: "German", + value: "de", + code: "deu", + }, + en: { + label: "English", + value: "en", + code: "eng", + }, + es: { + label: "Spanish", + value: "es", + code: "spa", + }, + fi: { + label: "Finnish", + value: "fi", + code: "fin", + }, + fr: { + label: "French", + value: "fr", + code: "fra", + }, + it: { + label: "Italian", + value: "it", + code: "ita", + }, + ja: { + label: "Japanese", + value: "ja", + code: "jpn", + }, + ko: { + label: "Korean", + value: "ko", + code: "kor", + }, + pt: { + label: "Portuguese", + value: "pt", + code: "por", + }, + ru: { + label: "Russian", + value: "ru", + code: "rus", + }, + tr: { + label: "Turkish", + value: "tr", + code: "tur", + }, + }