mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-23 18:10:26 +08:00
Merge branch 'main' into betterSqlite
This commit is contained in:
commit
36a9af3e6b
@ -89,6 +89,7 @@
|
|||||||
"@paymoapp/electron-shutdown-handler": "^1.1.2",
|
"@paymoapp/electron-shutdown-handler": "^1.1.2",
|
||||||
"@strongtz/win32-arm64-msvc": "^0.4.7",
|
"@strongtz/win32-arm64-msvc": "^0.4.7",
|
||||||
"better-sqlite3": "12.4.1",
|
"better-sqlite3": "12.4.1",
|
||||||
|
"emoji-picker-element-data": "^1",
|
||||||
"express": "^5.1.0",
|
"express": "^5.1.0",
|
||||||
"font-list": "^2.0.0",
|
"font-list": "^2.0.0",
|
||||||
"graceful-fs": "^4.2.11",
|
"graceful-fs": "^4.2.11",
|
||||||
|
|||||||
@ -1,35 +1,120 @@
|
|||||||
|
import 'emoji-picker-element'
|
||||||
|
|
||||||
import TwemojiCountryFlagsWoff2 from '@renderer/assets/fonts/country-flag-fonts/TwemojiCountryFlags.woff2?url'
|
import TwemojiCountryFlagsWoff2 from '@renderer/assets/fonts/country-flag-fonts/TwemojiCountryFlags.woff2?url'
|
||||||
import { useTheme } from '@renderer/context/ThemeProvider'
|
import { useTheme } from '@renderer/context/ThemeProvider'
|
||||||
|
import type { LanguageVarious } from '@renderer/types'
|
||||||
import { polyfillCountryFlagEmojis } from 'country-flag-emoji-polyfill'
|
import { polyfillCountryFlagEmojis } from 'country-flag-emoji-polyfill'
|
||||||
|
// i18n translations from emoji-picker-element
|
||||||
|
import de from 'emoji-picker-element/i18n/de'
|
||||||
|
import en from 'emoji-picker-element/i18n/en'
|
||||||
|
import es from 'emoji-picker-element/i18n/es'
|
||||||
|
import fr from 'emoji-picker-element/i18n/fr'
|
||||||
|
import ja from 'emoji-picker-element/i18n/ja'
|
||||||
|
import pt_PT from 'emoji-picker-element/i18n/pt_PT'
|
||||||
|
import ru_RU from 'emoji-picker-element/i18n/ru_RU'
|
||||||
|
import zh_CN from 'emoji-picker-element/i18n/zh_CN'
|
||||||
|
import type Picker from 'emoji-picker-element/picker'
|
||||||
|
import type { EmojiClickEvent, NativeEmoji } from 'emoji-picker-element/shared'
|
||||||
|
// Emoji data from emoji-picker-element-data (local, no CDN)
|
||||||
|
// Using CLDR format for full multi-language search support (28 languages)
|
||||||
|
import dataDE from 'emoji-picker-element-data/de/cldr/data.json?url'
|
||||||
|
import dataEN from 'emoji-picker-element-data/en/cldr/data.json?url'
|
||||||
|
import dataES from 'emoji-picker-element-data/es/cldr/data.json?url'
|
||||||
|
import dataFR from 'emoji-picker-element-data/fr/cldr/data.json?url'
|
||||||
|
import dataJA from 'emoji-picker-element-data/ja/cldr/data.json?url'
|
||||||
|
import dataPT from 'emoji-picker-element-data/pt/cldr/data.json?url'
|
||||||
|
import dataRU from 'emoji-picker-element-data/ru/cldr/data.json?url'
|
||||||
|
import dataZH from 'emoji-picker-element-data/zh/cldr/data.json?url'
|
||||||
|
import dataZH_HANT from 'emoji-picker-element-data/zh-hant/cldr/data.json?url'
|
||||||
import type { FC } from 'react'
|
import type { FC } from 'react'
|
||||||
import { useEffect, useRef } from 'react'
|
import { useEffect, useRef } from 'react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
onEmojiClick: (emoji: string) => void
|
onEmojiClick: (emoji: string) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mapping from app locale to emoji-picker-element i18n
|
||||||
|
const i18nMap: Record<LanguageVarious, typeof en> = {
|
||||||
|
'en-US': en,
|
||||||
|
'zh-CN': zh_CN,
|
||||||
|
'zh-TW': zh_CN, // Closest available
|
||||||
|
'de-DE': de,
|
||||||
|
'el-GR': en, // No Greek available, fallback to English
|
||||||
|
'es-ES': es,
|
||||||
|
'fr-FR': fr,
|
||||||
|
'ja-JP': ja,
|
||||||
|
'pt-PT': pt_PT,
|
||||||
|
'ru-RU': ru_RU
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mapping from app locale to emoji data URL
|
||||||
|
// Using CLDR format provides native language search support for all locales
|
||||||
|
const dataSourceMap: Record<LanguageVarious, string> = {
|
||||||
|
'en-US': dataEN,
|
||||||
|
'zh-CN': dataZH,
|
||||||
|
'zh-TW': dataZH_HANT,
|
||||||
|
'de-DE': dataDE,
|
||||||
|
'el-GR': dataEN, // No Greek CLDR available, fallback to English
|
||||||
|
'es-ES': dataES,
|
||||||
|
'fr-FR': dataFR,
|
||||||
|
'ja-JP': dataJA,
|
||||||
|
'pt-PT': dataPT,
|
||||||
|
'ru-RU': dataRU
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mapping from app locale to emoji-picker-element locale string
|
||||||
|
// Must match the data source locale for proper IndexedDB caching
|
||||||
|
const localeMap: Record<LanguageVarious, string> = {
|
||||||
|
'en-US': 'en',
|
||||||
|
'zh-CN': 'zh',
|
||||||
|
'zh-TW': 'zh-hant',
|
||||||
|
'de-DE': 'de',
|
||||||
|
'el-GR': 'en',
|
||||||
|
'es-ES': 'es',
|
||||||
|
'fr-FR': 'fr',
|
||||||
|
'ja-JP': 'ja',
|
||||||
|
'pt-PT': 'pt',
|
||||||
|
'ru-RU': 'ru'
|
||||||
|
}
|
||||||
|
|
||||||
const EmojiPicker: FC<Props> = ({ onEmojiClick }) => {
|
const EmojiPicker: FC<Props> = ({ onEmojiClick }) => {
|
||||||
const { theme } = useTheme()
|
const { theme } = useTheme()
|
||||||
const ref = useRef<HTMLDivElement>(null)
|
const { i18n } = useTranslation()
|
||||||
|
const ref = useRef<Picker>(null)
|
||||||
|
const currentLocale = i18n.language as LanguageVarious
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
polyfillCountryFlagEmojis('Twemoji Mozilla', TwemojiCountryFlagsWoff2)
|
polyfillCountryFlagEmojis('Twemoji Mozilla', TwemojiCountryFlagsWoff2)
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
// Configure picker with i18n and dataSource
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const refValue = ref.current
|
const picker = ref.current
|
||||||
|
if (picker) {
|
||||||
|
picker.i18n = i18nMap[currentLocale] || en
|
||||||
|
picker.dataSource = dataSourceMap[currentLocale] || dataEN
|
||||||
|
picker.locale = localeMap[currentLocale] || 'en'
|
||||||
|
}
|
||||||
|
}, [currentLocale])
|
||||||
|
|
||||||
if (refValue) {
|
useEffect(() => {
|
||||||
const handleEmojiClick = (event: any) => {
|
const picker = ref.current
|
||||||
|
|
||||||
|
if (picker) {
|
||||||
|
const handleEmojiClick = (event: EmojiClickEvent) => {
|
||||||
event.stopPropagation()
|
event.stopPropagation()
|
||||||
onEmojiClick(event.detail.unicode || event.detail.emoji.unicode)
|
const { detail } = event
|
||||||
|
// Use detail.unicode (processed with skin tone) or fallback to emoji's unicode for native emoji
|
||||||
|
const unicode = detail.unicode || ('unicode' in detail.emoji ? (detail.emoji as NativeEmoji).unicode : '')
|
||||||
|
onEmojiClick(unicode)
|
||||||
}
|
}
|
||||||
// 添加事件监听器
|
// 添加事件监听器
|
||||||
refValue.addEventListener('emoji-click', handleEmojiClick)
|
picker.addEventListener('emoji-click', handleEmojiClick)
|
||||||
|
|
||||||
// 清理事件监听器
|
// 清理事件监听器
|
||||||
return () => {
|
return () => {
|
||||||
refValue.removeEventListener('emoji-click', handleEmojiClick)
|
picker.removeEventListener('emoji-click', handleEmojiClick)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
|||||||
@ -1,5 +1,3 @@
|
|||||||
import 'emoji-picker-element'
|
|
||||||
|
|
||||||
import { CheckOutlined, LoadingOutlined, RollbackOutlined, ThunderboltOutlined } from '@ant-design/icons'
|
import { CheckOutlined, LoadingOutlined, RollbackOutlined, ThunderboltOutlined } from '@ant-design/icons'
|
||||||
import { loggerService } from '@logger'
|
import { loggerService } from '@logger'
|
||||||
import EmojiPicker from '@renderer/components/EmojiPicker'
|
import EmojiPicker from '@renderer/components/EmojiPicker'
|
||||||
|
|||||||
@ -10085,6 +10085,7 @@ __metadata:
|
|||||||
electron-window-state: "npm:^5.0.3"
|
electron-window-state: "npm:^5.0.3"
|
||||||
emittery: "npm:^1.0.3"
|
emittery: "npm:^1.0.3"
|
||||||
emoji-picker-element: "npm:^1.22.1"
|
emoji-picker-element: "npm:^1.22.1"
|
||||||
|
emoji-picker-element-data: "npm:^1"
|
||||||
epub: "patch:epub@npm%3A1.3.0#~/.yarn/patches/epub-npm-1.3.0-8325494ffe.patch"
|
epub: "patch:epub@npm%3A1.3.0#~/.yarn/patches/epub-npm-1.3.0-8325494ffe.patch"
|
||||||
eslint: "npm:^9.22.0"
|
eslint: "npm:^9.22.0"
|
||||||
eslint-plugin-import-zod: "npm:^1.2.0"
|
eslint-plugin-import-zod: "npm:^1.2.0"
|
||||||
@ -13686,6 +13687,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"emoji-picker-element-data@npm:^1":
|
||||||
|
version: 1.8.0
|
||||||
|
resolution: "emoji-picker-element-data@npm:1.8.0"
|
||||||
|
checksum: 10c0/c8976b636205a0cc90d2690859a1193add71a948dadf743962b47c338a4c3715768404d0ccbc02156608b44abf41f3e1d51756e06f1bbed9d164dd4cb1752103
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"emoji-picker-element@npm:^1.22.1":
|
"emoji-picker-element@npm:^1.22.1":
|
||||||
version: 1.26.3
|
version: 1.26.3
|
||||||
resolution: "emoji-picker-element@npm:1.26.3"
|
resolution: "emoji-picker-element@npm:1.26.3"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user