Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions frontend/src/components/CalendarSubscriptionModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -79,16 +79,16 @@ async function copyUrl() {
<div class="calendar-guide-section">
<h4>{{ tr('快速配置指南', 'Quick Setup Guide') }}</h4>
<div class="guide-item">
<strong>🍎 {{ tr('Apple 日历 (Mac / iOS)', 'Apple Calendar (Mac / iOS)') }}</strong>
<span>{{ tr('文件 ➔ 新建日历订阅 ➔ 粘贴上方链接 ➔ 自动刷新建议选择“每小时”。', 'File ➔ New Calendar Subscription ➔ Paste URL ➔ Set Auto-refresh to Every Hour.') }}</span>
<strong>{{ tr('Apple 日历 (Mac / iOS)', 'Apple Calendar (Mac / iOS)') }}</strong>
<span>{{ tr('文件 / 新建日历订阅 / 粘贴上方链接 / 自动刷新建议选择“每小时”。', 'File / New Calendar Subscription / Paste URL / Set Auto-refresh to Every Hour.') }}</span>
</div>
<div class="guide-item">
<strong>📅 Google Calendar</strong>
<span>{{ tr('其他日历旁点击 “+” ➔ 通过网址添加 ➔ 粘贴链接 ➔ 添加日历。', 'Click "+" next to Other calendars ➔ From URL ➔ Paste URL ➔ Add calendar.') }}</span>
<strong>Google Calendar</strong>
<span>{{ tr('其他日历旁点击 “+” / 通过网址添加 / 粘贴链接 / 添加日历。', 'Click "+" next to Other calendars / From URL / Paste URL / Add calendar.') }}</span>
</div>
<div class="guide-item">
<strong>📧 Microsoft Outlook</strong>
<span>{{ tr('添加日历 ➔ 从 Web 订阅 ➔ 粘贴链接并保存。', 'Add calendar ➔ Subscribe from web ➔ Paste URL and save.') }}</span>
<strong>Microsoft Outlook</strong>
<span>{{ tr('添加日历 / 从 Web 订阅 / 粘贴链接并保存。', 'Add calendar / Subscribe from web / Paste URL and save.') }}</span>
</div>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/WebhookNotifyModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ async function sendNotification() {

<div class="card-preview-box">
<span class="preview-tag">{{ tr('推送内容预览', 'Card Preview') }}</span>
<div class="preview-title">📋 {{ tr('会议纪要:', 'Meeting Summary: ') }}{{ meeting.title }}</div>
<div class="preview-title">{{ tr('会议纪要:', 'Meeting Summary: ') }}{{ meeting.title }}</div>
<div class="preview-meta">
<span>{{ tr('状态:', 'Status: ') }}{{ meeting.status === 'completed' ? tr('已完成', 'Completed') : tr('进行中', 'In Progress') }}</span> ·
<span>{{ tr('议题数:', 'Agendas: ') }}{{ meeting.agenda_items.length }}</span>
Expand Down
25 changes: 13 additions & 12 deletions frontend/src/i18n/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -231,15 +231,15 @@ export const SEEDED_ZH_TO_EN: Record<string, string> = {
'聚焦会前准备、会中专注研讨与会后归档闭环。':
'Focus on pre-meeting prep, live focused discussion, and post-meeting archive loop.',
'Q3 架构演进与中英双语体验评审': 'Q3 Architecture Evolution & Bilingual UX Review',
'评审页内 ✨ AI 智能提炼、双向行动项状态机及中英双语无缝切换体验。':
'Review in-place ✨ AI Smart Extract, two-way action state machine, and seamless bilingual switching.',
'页内 ✨ AI 智能提炼与结构化产出': 'In-place ✨ AI Smart Extract & Structured Outcomes',
'评审页内 AI 智能提炼、双向行动项状态机及中英双语无缝切换体验。':
'Review in-place AI Smart Extract, two-way action state machine, and seamless bilingual switching.',
'页内 AI 智能提炼与结构化产出': 'In-place AI Smart Extract & Structured Outcomes',
'围绕会议记录与 AI 提炼流程达成以下结论:':
'Key conclusions on meeting notes and AI extraction workflow:',
'团队一致决定采用页内 ✨ AI 智能提炼直接写入当前议题记录,彻底移除冗余弹窗':
'Unanimously decided to use in-place ✨ AI Smart Extract directly in agenda notes, removing redundant modals',
'采用页内 ✨ AI 智能提炼直接写入当前议题记录,彻底移除冗余弹窗':
'Use in-place ✨ AI Smart Extract directly in agenda notes, removing redundant modals',
'团队一致决定采用页内 AI 智能提炼直接写入当前议题记录,彻底移除冗余弹窗':
'Unanimously decided to use in-place AI Smart Extract directly in agenda notes, removing redundant modals',
'采用页内 AI 智能提炼直接写入当前议题记录,彻底移除冗余弹窗':
'Use in-place AI Smart Extract directly in agenda notes, removing redundant modals',
'请 @admin 完善中英双语标签 (@决策/@Decision、@行动/@Action) 解析与单元测试':
'Please @admin refine bilingual tag (@Decision, @Action) parsing and unit tests',
'完善中英双语标签 (@决策/@Decision、@行动/@Action) 解析与单元测试':
Expand All @@ -266,8 +266,8 @@ export const SEEDED_ZH_TO_EN: Record<string, string> = {
'周会例行同步': 'Weekly Sync',
'双周架构评审': 'Bi-weekly Architecture Review',
'每周三 10:00 固定同步': 'Every Wednesday at 10:00',
'确认采用页内 ✨ AI 智能提炼直接写入当前议题记录,彻底移除冗余弹窗':
'Confirm in-place ✨ AI Smart Extract directly in agenda notes, removing redundant modals',
'确认采用页内 AI 智能提炼直接写入当前议题记录,彻底移除冗余弹窗':
'Confirm in-place AI Smart Extract directly in agenda notes, removing redundant modals',
}

export const SEEDED_EN_TO_ZH: Record<string, string> = Object.fromEntries(
Expand All @@ -279,7 +279,8 @@ const SORTED_EN_ENTRIES = Object.entries(SEEDED_EN_TO_ZH).sort((a, b) => b[0].le

export function translateSeededText(text: string, lang: Locale = locale.value): string {
if (!text) return text
const trimmed = text.trim()
const cleaned = text.replace(/\u2728\s*/g, '')
const trimmed = cleaned.trim()
if (lang === 'en') {
if (SEEDED_ZH_TO_EN[trimmed]) return SEEDED_ZH_TO_EN[trimmed]
const discussMatch = trimmed.match(/^###\s+(.+?)\s+·\s+讨论要点$/)
Expand Down Expand Up @@ -310,7 +311,7 @@ export function translateSeededText(text: string, lang: Locale = locale.value):
if (qFallbackMatch) {
return `Cross-module boundary details for "${translateSeededText(qFallbackMatch[1], 'en')}" pending final confirmation`
}
let replaced = text
let replaced = cleaned
for (const [zh, en] of SORTED_ZH_ENTRIES) {
if (zh.length >= 4 && replaced.includes(zh)) {
replaced = replaced.split(zh).join(en)
Expand Down Expand Up @@ -348,7 +349,7 @@ export function translateSeededText(text: string, lang: Locale = locale.value):
if (enQFallbackMatch) {
return `「${translateSeededText(enQFallbackMatch[1], 'zh')}」跨模块边界细节待最终确认`
}
let replaced = text
let replaced = cleaned
for (const [en, zh] of SORTED_EN_ENTRIES) {
if (en.length >= 6 && replaced.includes(en)) {
replaced = replaced.split(en).join(zh)
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/tests/focus-and-integrations.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ describe('P0 Features: Bidirectional Actions, Focus Mode, Calendar & Webhooks',
expect(screen.getByLabelText('议题记录')).toHaveValue('正在输入的未保存笔记内容')
})

it('structures and extracts decisions, actions, and open questions in-place via ✨ AI 智能提炼', async () => {
it('structures and extracts decisions, actions, and open questions in-place via AI 智能提炼', async () => {
const meeting = meetingFixture()
apiMock.mockImplementation((url: string, init?: RequestInit) => {
if (url === '/api/v1/meetings/m1/ingest' && init?.method === 'POST') {
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/tests/ui-foundation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ describe('icon glyph policy', () => {
it('uses lucide svg icons instead of unicode glyphs in the source tree', () => {
// Spec §4.3: functional icons must be Lucide SVG wrapped in NIcon; the brand "M"
// mark (a logo, not a functional icon) is explicitly kept and is not in this list.
const forbidden = ['⌕', '•••', '✓', '○', '→', '⌁', '⌄', '×', '✕', '✦', '◎', '●']
const forbidden = ['⌕', '•••', '✓', '○', '→', '⌁', '⌄', '×', '✕', '✦', '◎', '●', '📋', '🍎', '📅', '📧', '✨']
const sources = import.meta.glob(['../**/*.vue', '../**/*.ts', '../**/*.css'], {
query: '?raw',
import: 'default',
Expand Down
Loading