diff --git a/components/email/__tests__/composer-mv-window.test.tsx b/components/email/__tests__/composer-mv-window.test.tsx index 1609ce6b1..5b0407095 100644 --- a/components/email/__tests__/composer-mv-window.test.tsx +++ b/components/email/__tests__/composer-mv-window.test.tsx @@ -2,7 +2,7 @@ import { render, screen, fireEvent } from '@testing-library/react'; import { describe, it, expect, vi, beforeEach } from 'vitest'; import React from 'react'; import { EmailComposer } from '../email-composer'; -import { MvComposeWindow } from '../mv-compose-window'; +import { MvComposeInline, MvComposeWindow } from '../mv-compose-window'; // ─── Heavy component mocks (mirrors reply-addressing.test.tsx) ──────────────── @@ -227,6 +227,16 @@ describe('composer in the Mountain View compose window', () => { expect(editor).toHaveAttribute('data-placement', 'bottom'); }); + it('writes a reply in place with a bar that pops it out, and no window controls', () => { + const onPopOut = vi.fn(); + render(); + expect(document.querySelector('[data-mv-compose-inline-bar]')).not.toBeNull(); + expect(screen.queryByRole('button', { name: 'minimize' })).toBeNull(); + + fireEvent.click(screen.getByRole('button', { name: 'pop_out' })); + expect(onPopOut).toHaveBeenCalledTimes(1); + }); + it('keeps its own header and a top toolbar outside the window', () => { render(); expect(document.querySelector('[data-mv-compose-titlebar]')).toBeNull(); diff --git a/components/email/email-composer.tsx b/components/email/email-composer.tsx index f3b11f74c..fe3f3160d 100644 --- a/components/email/email-composer.tsx +++ b/components/email/email-composer.tsx @@ -29,6 +29,10 @@ import { Maximize2, Minimize2, Trash2, + ExternalLink, + ReplyAll, + Reply, + Forward, } from "@/components/icons"; import { ComposerToolbarMenu, ComposerToolbarMenuItem, ComposerToolbarMenuCheckItem } from "@/components/email/composer-toolbar-menu"; import { cn, formatFileSize, formatDateTime, generateUUID } from "@/lib/utils"; @@ -3012,7 +3016,39 @@ export function EmailComposer({ )} {/* Header - mobile: clean bar with close/send, desktop: title bar. In Mountain View's window it is the window's title bar instead. */} - {mvWindow ? ( + {mvWindow?.variant === "inline" ? ( +
+ {mode === 'replyAll' + ? + : mode === 'forward' + ? + : } +

+ {mode === 'reply' ? t('reply') : mode === 'replyAll' ? t('reply_all') : mode === 'forward' ? t('forward') : t('new_message')} +

+ {saveStatus === 'saving' && } + {mvWindow.popOut && ( + + )} + +
+ ) : mvWindow ? (
void; + /** Mountain View: a reply being written in place, shown under the conversation instead of the reply buttons. */ + mvInlineComposer?: React.ReactNode; onShowShortcuts?: () => void; onEditDraft?: () => void; onCancelScheduledForEdit?: () => void; @@ -809,6 +811,7 @@ export function EmailViewer({ mvFolderName, mvConversation, onOpenConversationEmail, + mvInlineComposer, onShowShortcuts, onEditDraft, onCancelScheduledForEdit, @@ -5551,8 +5554,15 @@ export function EmailViewer({
)} + {/* Mountain View: a reply being written in place. */} + {mvViewer && mvInlineComposer && ( +
el?.scrollIntoView({ block: 'nearest' })}> + {mvInlineComposer} +
+ )} + {/* Mountain View: Reply / Reply all / Forward as buttons under the message. */} - {mvReplyRow && !isDraft && !isScheduled && !isBodyLoading && (effectiveEmailContent.isHtml ? iframeReady : true) && ( + {mvReplyRow && !(mvViewer && mvInlineComposer) && !isDraft && !isScheduled && !isBodyLoading && (effectiveEmailContent.isHtml ? iframeReady : true) && (
void; + /** Inline only: move the reply into a docked window. */ + popOut?: () => void; } export const MvComposeWindowContext = createContext(null); diff --git a/components/email/mv-compose-window.tsx b/components/email/mv-compose-window.tsx index 6a4d8d340..2f6317266 100644 --- a/components/email/mv-compose-window.tsx +++ b/components/email/mv-compose-window.tsx @@ -15,7 +15,7 @@ export function MvComposeWindow({ children }: { children: ReactNode }) { const [state, setState] = useState("normal"); const minimized = state === "minimized"; const maximized = state === "maximized"; - const controls = useMemo(() => ({ state, setState }), [state]); + const controls = useMemo(() => ({ variant: "window" as const, state, setState }), [state]); return ( @@ -43,3 +43,27 @@ export function MvComposeWindow({ children }: { children: ReactNode }) { ); } + +const NOOP = () => {}; + +/** + * Mountain View's inline reply: the composer as a card under the open + * conversation, as Gmail writes replies, with a button that pops it out into + * the docked window. + */ +export function MvComposeInline({ children, onPopOut }: { children: ReactNode; onPopOut: () => void }) { + const controls = useMemo( + () => ({ variant: "inline" as const, state: "normal" as const, setState: NOOP, popOut: onPopOut }), + [onPopOut], + ); + return ( + +
+ {children} +
+
+ ); +} diff --git a/components/mail/mail-app.tsx b/components/mail/mail-app.tsx index e8e8107d1..662cd373f 100644 --- a/components/mail/mail-app.tsx +++ b/components/mail/mail-app.tsx @@ -5,7 +5,7 @@ import { usePathname } from "next/navigation"; import { useTranslations } from "next-intl"; import { Sidebar } from "@/components/layout/sidebar"; import { EmailList } from "@/components/email/email-list"; -import { MvComposeWindow } from "@/components/email/mv-compose-window"; +import { MvComposeInline, MvComposeWindow } from "@/components/email/mv-compose-window"; import { MessageListTabs } from "@/components/email/message-list-tabs"; import dynamic from "next/dynamic"; import type { ComposerDraftData } from "@/components/email/email-composer"; @@ -201,6 +201,13 @@ export function MailApp({ linkSegments: routeSegments }: MailAppProps = {}) { const dragStartWidth = useRef(0); // Mobile conversation view state const [conversationThread, setConversationThread] = useState(null); + // Mountain View writes replies in place under the conversation until the + // user pops one out into the docked window. + const [mvReplyPoppedOut, setMvReplyPoppedOut] = useState(false); + useEffect(() => { + if (!showComposer) setMvReplyPoppedOut(false); + }, [showComposer]); + const handleMvPopOut = useCallback(() => setMvReplyPoppedOut(true), []); // Mountain View: the open message's whole conversation, light properties only. const [mvConversation, setMvConversation] = useState(null); const [conversationEmails, setConversationEmails] = useState([]); @@ -3618,7 +3625,9 @@ export function MailApp({ linkSegments: routeSegments }: MailAppProps = {}) { const isHorizontalMailLayout = mailLayout === 'horizontal' && !isMobile && !isTablet; // Under Mountain View on desktop the composer floats over the list in a // docked window instead of taking the reading pane. - const floatingComposer = mvShell && showComposer && !isEmbedded; + const mvInlineReply = mvShell && showComposer && !isEmbedded && !mvReplyPoppedOut + && (pendingDraft?.mode ?? composerMode) !== 'compose' && Boolean(selectedEmail); + const floatingComposer = mvShell && showComposer && !isEmbedded && !mvInlineReply; const hasViewerContent = (showComposer && !floatingComposer) || Boolean(conversationThread) || Boolean(selectedEmail && !(mvShell && cursorOnly)); const shouldCollapseListPane = (isTablet && !tabletListVisible && !readingPaneEmpty) || (!isMobile && isFocusedMailLayout && hasViewerContent); @@ -4651,7 +4660,7 @@ export function MailApp({ linkSegments: routeSegments }: MailAppProps = {}) { {/* Inline Composer - shown in viewer pane. In Pro/embedded mode the composer is hoisted into its own Pro tab (see the effect below), so we never render it inline. */} - {(showComposer && !isEmbedded && !floatingComposer) ? composerNode : ( + {(showComposer && !isEmbedded && !floatingComposer && !mvInlineReply) ? composerNode : ( <> {/* Pending draft banner */} {pendingDraft && ( @@ -4753,6 +4762,7 @@ export function MailApp({ linkSegments: routeSegments }: MailAppProps = {}) { mvFolderName={mvShell && !isScheduledView && !isUnifiedView ? currentMailboxName : undefined} mvConversation={mvShell ? mvConversation ?? undefined : undefined} onOpenConversationEmail={mvShell ? (e) => void handleEmailSelect(e) : undefined} + mvInlineComposer={mvInlineReply ? {composerNode} : undefined} onToggleFullscreen={!isEmbedded && !isMobile ? () => setFullscreenReading((v) => !v) : undefined} isFullscreen={fullscreenReading} onShowShortcuts={() => setShowShortcutsModal(true)} diff --git a/locales/ar/common.json b/locales/ar/common.json index 35c97d117..7abcb9416 100644 --- a/locales/ar/common.json +++ b/locales/ar/common.json @@ -803,7 +803,8 @@ "background_color": "لون الخلفية", "remove_background_color": "إزالة لون الخلفية" }, - "send_filing_warning": "تم الإرسال - لكن التنظيف بعد الإرسال فشل، وقد تبقى مسودة قديمة." + "send_filing_warning": "تم الإرسال - لكن التنظيف بعد الإرسال فشل، وقد تبقى مسودة قديمة.", + "pop_out": "فتح الرد في نافذة منفصلة" }, "confirm_dialog": { "confirm": "تأكيد", diff --git a/locales/ca/common.json b/locales/ca/common.json index e397d90a2..f528c6e88 100644 --- a/locales/ca/common.json +++ b/locales/ca/common.json @@ -803,7 +803,8 @@ "background_color": "Color de fons", "remove_background_color": "Elimina el color de fons" }, - "send_filing_warning": "Enviat, però la neteja posterior a l'enviament ha fallat; és possible que quedi un esborrany obsolet." + "send_filing_warning": "Enviat, però la neteja posterior a l'enviament ha fallat; és possible que quedi un esborrany obsolet.", + "pop_out": "Obre la resposta en una finestra" }, "confirm_dialog": { "confirm": "Confirma", diff --git a/locales/cs/common.json b/locales/cs/common.json index 3a1f4b82d..13365c401 100644 --- a/locales/cs/common.json +++ b/locales/cs/common.json @@ -803,7 +803,8 @@ "background_color": "Barva pozadí", "remove_background_color": "Odebrat barvu pozadí" }, - "send_filing_warning": "Odesláno - ale následný úklid selhal, může zůstat zastaralý koncept." + "send_filing_warning": "Odesláno - ale následný úklid selhal, může zůstat zastaralý koncept.", + "pop_out": "Otevřít odpověď v okně" }, "confirm_dialog": { "confirm": "Potvrdit", diff --git a/locales/da/common.json b/locales/da/common.json index 61c9c7824..ad39eb9c8 100644 --- a/locales/da/common.json +++ b/locales/da/common.json @@ -803,7 +803,8 @@ "background_color": "Baggrundsfarve", "remove_background_color": "Fjern baggrundsfarve" }, - "send_filing_warning": "Sendt - men oprydningen bagefter mislykkedes, en forældet kladde kan blive stående." + "send_filing_warning": "Sendt - men oprydningen bagefter mislykkedes, en forældet kladde kan blive stående.", + "pop_out": "Åbn svaret i et vindue" }, "confirm_dialog": { "confirm": "Bekræft", diff --git a/locales/de/common.json b/locales/de/common.json index 630d18a11..2f1f8f893 100644 --- a/locales/de/common.json +++ b/locales/de/common.json @@ -803,7 +803,8 @@ "background_color": "Hintergrundfarbe", "remove_background_color": "Hintergrundfarbe entfernen" }, - "send_filing_warning": "Gesendet - aber das Aufräumen danach schlug fehl, evtl. bleibt ein alter Entwurf sichtbar." + "send_filing_warning": "Gesendet - aber das Aufräumen danach schlug fehl, evtl. bleibt ein alter Entwurf sichtbar.", + "pop_out": "Antwort in eigenem Fenster öffnen" }, "confirm_dialog": { "confirm": "Bestätigen", diff --git a/locales/en/common.json b/locales/en/common.json index b517c92fd..4988fb56d 100644 --- a/locales/en/common.json +++ b/locales/en/common.json @@ -803,7 +803,8 @@ "background_color": "Background color", "remove_background_color": "Remove background color" }, - "send_filing_warning": "Sent - but the post-send cleanup failed, a stale draft may remain." + "send_filing_warning": "Sent - but the post-send cleanup failed, a stale draft may remain.", + "pop_out": "Pop out reply" }, "confirm_dialog": { "confirm": "Confirm", diff --git a/locales/es/common.json b/locales/es/common.json index efd614354..7ce5639f5 100644 --- a/locales/es/common.json +++ b/locales/es/common.json @@ -803,7 +803,8 @@ "background_color": "Color de fondo", "remove_background_color": "Quitar color de fondo" }, - "send_filing_warning": "Enviado - pero la limpieza posterior falló, puede quedar un borrador obsoleto." + "send_filing_warning": "Enviado - pero la limpieza posterior falló, puede quedar un borrador obsoleto.", + "pop_out": "Abrir la respuesta en una ventana" }, "confirm_dialog": { "confirm": "Confirmar", diff --git a/locales/fa/common.json b/locales/fa/common.json index d10f9411b..0a8edf6cc 100644 --- a/locales/fa/common.json +++ b/locales/fa/common.json @@ -803,7 +803,8 @@ "background_color": "رنگ پس‌زمینه", "remove_background_color": "حذف رنگ پس‌زمینه" }, - "send_filing_warning": "ارسال شد - اما پاک‌سازی پس از ارسال ناموفق بود، ممکن است پیش‌نویس قدیمی باقی بماند." + "send_filing_warning": "ارسال شد - اما پاک‌سازی پس از ارسال ناموفق بود، ممکن است پیش‌نویس قدیمی باقی بماند.", + "pop_out": "باز کردن پاسخ در پنجره جدا" }, "confirm_dialog": { "confirm": "تأیید", diff --git a/locales/fr/common.json b/locales/fr/common.json index 449a2d170..e2f0734a7 100644 --- a/locales/fr/common.json +++ b/locales/fr/common.json @@ -803,7 +803,8 @@ "background_color": "Couleur d'arrière-plan", "remove_background_color": "Supprimer la couleur d'arrière-plan" }, - "send_filing_warning": "Envoyé - mais le nettoyage après envoi a échoué, un ancien brouillon peut subsister." + "send_filing_warning": "Envoyé - mais le nettoyage après envoi a échoué, un ancien brouillon peut subsister.", + "pop_out": "Ouvrir la réponse dans une fenêtre" }, "confirm_dialog": { "confirm": "Confirmer", diff --git a/locales/he/common.json b/locales/he/common.json index 365ce47cc..625fa8081 100644 --- a/locales/he/common.json +++ b/locales/he/common.json @@ -768,7 +768,8 @@ "background_color": "צבע רקע", "remove_background_color": "הסר צבע רקע" }, - "send_filing_warning": "נשלח - אך הניקוי שלאחר השליחה נכשל, ייתכן שתישאר טיוטה ישנה." + "send_filing_warning": "נשלח - אך הניקוי שלאחר השליחה נכשל, ייתכן שתישאר טיוטה ישנה.", + "pop_out": "פתיחת התשובה בחלון נפרד" }, "confirm_dialog": { "confirm": "אשר", diff --git a/locales/hu/common.json b/locales/hu/common.json index 86f115187..d99cef733 100644 --- a/locales/hu/common.json +++ b/locales/hu/common.json @@ -803,7 +803,8 @@ "background_color": "Háttérszín", "remove_background_color": "Háttérszín eltávolítása" }, - "send_filing_warning": "Elküldve - de az utólagos rendrakás nem sikerült, egy elavult piszkozat megmaradhat." + "send_filing_warning": "Elküldve - de az utólagos rendrakás nem sikerült, egy elavult piszkozat megmaradhat.", + "pop_out": "Válasz megnyitása külön ablakban" }, "confirm_dialog": { "confirm": "Megerősítés", diff --git a/locales/it/common.json b/locales/it/common.json index 0adbcdc83..5685775a8 100644 --- a/locales/it/common.json +++ b/locales/it/common.json @@ -803,7 +803,8 @@ "background_color": "Colore di sfondo", "remove_background_color": "Rimuovi colore di sfondo" }, - "send_filing_warning": "Inviato - ma la pulizia successiva non è riuscita, potrebbe restare una bozza obsoleta." + "send_filing_warning": "Inviato - ma la pulizia successiva non è riuscita, potrebbe restare una bozza obsoleta.", + "pop_out": "Apri la risposta in una finestra" }, "confirm_dialog": { "confirm": "Conferma", diff --git a/locales/ja/common.json b/locales/ja/common.json index 2f1fb0f30..ebab1007e 100644 --- a/locales/ja/common.json +++ b/locales/ja/common.json @@ -803,7 +803,8 @@ "background_color": "背景色", "remove_background_color": "背景色を削除" }, - "send_filing_warning": "送信されましたが、送信後の整理に失敗しました。古い下書きが残る場合があります。" + "send_filing_warning": "送信されましたが、送信後の整理に失敗しました。古い下書きが残る場合があります。", + "pop_out": "返信を別ウィンドウで開く" }, "confirm_dialog": { "confirm": "確認", diff --git a/locales/ko/common.json b/locales/ko/common.json index b969e3dc4..d13ed38d1 100644 --- a/locales/ko/common.json +++ b/locales/ko/common.json @@ -803,7 +803,8 @@ "background_color": "배경색", "remove_background_color": "배경색 제거" }, - "send_filing_warning": "보냈지만 전송 후 정리에 실패했습니다. 오래된 임시 보관 메일이 남아 있을 수 있습니다." + "send_filing_warning": "보냈지만 전송 후 정리에 실패했습니다. 오래된 임시 보관 메일이 남아 있을 수 있습니다.", + "pop_out": "답장을 별도 창에서 열기" }, "confirm_dialog": { "confirm": "확인", diff --git a/locales/lv/common.json b/locales/lv/common.json index 9ea540479..1e52d33ea 100644 --- a/locales/lv/common.json +++ b/locales/lv/common.json @@ -803,7 +803,8 @@ "background_color": "Fona krāsa", "remove_background_color": "Noņemt fona krāsu" }, - "send_filing_warning": "Nosūtīts - bet pēcapstrāde neizdevās, var palikt novecojis melnraksts." + "send_filing_warning": "Nosūtīts - bet pēcapstrāde neizdevās, var palikt novecojis melnraksts.", + "pop_out": "Atvērt atbildi atsevišķā logā" }, "confirm_dialog": { "confirm": "Apstiprināt", diff --git a/locales/mn/common.json b/locales/mn/common.json index 8c97812fe..86a3e6cb8 100644 --- a/locales/mn/common.json +++ b/locales/mn/common.json @@ -803,7 +803,8 @@ "background_color": "Дэвсгэр өнгө", "remove_background_color": "Дэвсгэр өнгийг арилгах" }, - "send_filing_warning": "Илгээсэн - гэхдээ илгээсний дараах цэвэрлэгээ амжилтгүй болсон тул хуучирсан ноорог үлдэж болзошгүй." + "send_filing_warning": "Илгээсэн - гэхдээ илгээсний дараах цэвэрлэгээ амжилтгүй болсон тул хуучирсан ноорог үлдэж болзошгүй.", + "pop_out": "Хариуг тусдаа цонхонд нээх" }, "confirm_dialog": { "confirm": "Баталгаажуулах", diff --git a/locales/nb/common.json b/locales/nb/common.json index 535b9207d..ebd30645d 100644 --- a/locales/nb/common.json +++ b/locales/nb/common.json @@ -803,7 +803,8 @@ "background_color": "Bakgrunnsfarge", "remove_background_color": "Fjern bakgrunnsfarge" }, - "send_filing_warning": "Meldingen ble sendt, men oppryddingen etterpå mislyktes. Et gammelt utkast kan bli liggende." + "send_filing_warning": "Meldingen ble sendt, men oppryddingen etterpå mislyktes. Et gammelt utkast kan bli liggende.", + "pop_out": "Åpne svaret i et eget vindu" }, "confirm_dialog": { "confirm": "Bekreft", diff --git a/locales/nl/common.json b/locales/nl/common.json index f1ba111e0..e9a931954 100644 --- a/locales/nl/common.json +++ b/locales/nl/common.json @@ -803,7 +803,8 @@ "background_color": "Achtergrondkleur", "remove_background_color": "Achtergrondkleur verwijderen" }, - "send_filing_warning": "Verzonden - maar het opruimen daarna is mislukt, mogelijk blijft een oud concept staan." + "send_filing_warning": "Verzonden - maar het opruimen daarna is mislukt, mogelijk blijft een oud concept staan.", + "pop_out": "Antwoord in een apart venster openen" }, "confirm_dialog": { "confirm": "Bevestigen", diff --git a/locales/pl/common.json b/locales/pl/common.json index bb42bc4ab..bd56abd49 100644 --- a/locales/pl/common.json +++ b/locales/pl/common.json @@ -803,7 +803,8 @@ "background_color": "Kolor tła", "remove_background_color": "Usuń kolor tła" }, - "send_filing_warning": "Wysłano - ale późniejsze porządkowanie nie powiodło się, może pozostać nieaktualna wersja robocza." + "send_filing_warning": "Wysłano - ale późniejsze porządkowanie nie powiodło się, może pozostać nieaktualna wersja robocza.", + "pop_out": "Otwórz odpowiedź w oknie" }, "confirm_dialog": { "confirm": "Potwierdź", diff --git a/locales/pt/common.json b/locales/pt/common.json index c3e858de2..cfc50c836 100644 --- a/locales/pt/common.json +++ b/locales/pt/common.json @@ -803,7 +803,8 @@ "background_color": "Cor de fundo", "remove_background_color": "Remover cor de fundo" }, - "send_filing_warning": "Enviado - mas a limpeza posterior falhou, um rascunho antigo pode permanecer." + "send_filing_warning": "Enviado - mas a limpeza posterior falhou, um rascunho antigo pode permanecer.", + "pop_out": "Abrir a resposta numa janela" }, "confirm_dialog": { "confirm": "Confirmar", diff --git a/locales/ro/common.json b/locales/ro/common.json index 4a2edb614..2ff7378de 100644 --- a/locales/ro/common.json +++ b/locales/ro/common.json @@ -803,7 +803,8 @@ "background_color": "Culoarea fundalului", "remove_background_color": "Elimină culoarea fundalului" }, - "send_filing_warning": "Trimis - dar curățarea ulterioară a eșuat, poate rămâne o ciornă veche." + "send_filing_warning": "Trimis - dar curățarea ulterioară a eșuat, poate rămâne o ciornă veche.", + "pop_out": "Deschide răspunsul într-o fereastră" }, "confirm_dialog": { "confirm": "Confirmare", diff --git a/locales/ru/common.json b/locales/ru/common.json index fd91a3508..853a7898a 100644 --- a/locales/ru/common.json +++ b/locales/ru/common.json @@ -803,7 +803,8 @@ "background_color": "Цвет фона", "remove_background_color": "Убрать цвет фона" }, - "send_filing_warning": "Отправлено - но последующая очистка не удалась, может остаться устаревший черновик." + "send_filing_warning": "Отправлено - но последующая очистка не удалась, может остаться устаревший черновик.", + "pop_out": "Открыть ответ в отдельном окне" }, "confirm_dialog": { "confirm": "Подтвердить", diff --git a/locales/sk/common.json b/locales/sk/common.json index 9bfb28c6f..eff8918db 100644 --- a/locales/sk/common.json +++ b/locales/sk/common.json @@ -803,7 +803,8 @@ "background_color": "Farba pozadia", "remove_background_color": "Odstrániť farbu pozadia" }, - "send_filing_warning": "Odoslané - ale následné upratovanie zlyhalo, môže zostať zastaraný koncept." + "send_filing_warning": "Odoslané - ale následné upratovanie zlyhalo, môže zostať zastaraný koncept.", + "pop_out": "Otvoriť odpoveď v okne" }, "confirm_dialog": { "confirm": "Potvrdiť", diff --git a/locales/tr/common.json b/locales/tr/common.json index ec040734d..5ace198dd 100644 --- a/locales/tr/common.json +++ b/locales/tr/common.json @@ -803,7 +803,8 @@ "background_color": "Arka plan rengi", "remove_background_color": "Arka plan rengini kaldır" }, - "send_filing_warning": "Gönderildi - ancak sonrasındaki temizleme başarısız oldu, eski bir taslak kalabilir." + "send_filing_warning": "Gönderildi - ancak sonrasındaki temizleme başarısız oldu, eski bir taslak kalabilir.", + "pop_out": "Yanıtı ayrı pencerede aç" }, "confirm_dialog": { "confirm": "Onayla", diff --git a/locales/uk/common.json b/locales/uk/common.json index a86f4fe6a..b391acf76 100644 --- a/locales/uk/common.json +++ b/locales/uk/common.json @@ -803,7 +803,8 @@ "background_color": "Колір фону", "remove_background_color": "Прибрати колір фону" }, - "send_filing_warning": "Надіслано - але подальше очищення не вдалося, може залишитися застаріла чернетка." + "send_filing_warning": "Надіслано - але подальше очищення не вдалося, може залишитися застаріла чернетка.", + "pop_out": "Відкрити відповідь в окремому вікні" }, "confirm_dialog": { "confirm": "Підтвердити", diff --git a/locales/zh-TW/common.json b/locales/zh-TW/common.json index d08ab4f16..dbf7f831e 100644 --- a/locales/zh-TW/common.json +++ b/locales/zh-TW/common.json @@ -803,7 +803,8 @@ "background_color": "背景顏色", "remove_background_color": "移除背景顏色" }, - "send_filing_warning": "郵件已傳送,但寄送後清理失敗,可能仍保留舊草稿。" + "send_filing_warning": "郵件已傳送,但寄送後清理失敗,可能仍保留舊草稿。", + "pop_out": "在獨立視窗中開啟回覆" }, "confirm_dialog": { "confirm": "確認", diff --git a/locales/zh/common.json b/locales/zh/common.json index f9d71a8dd..07c73d9db 100644 --- a/locales/zh/common.json +++ b/locales/zh/common.json @@ -803,7 +803,8 @@ "background_color": "背景颜色", "remove_background_color": "移除背景颜色" }, - "send_filing_warning": "已发送,但发送后的清理失败,可能会残留旧草稿。" + "send_filing_warning": "已发送,但发送后的清理失败,可能会残留旧草稿。", + "pop_out": "在单独窗口中打开回复" }, "confirm_dialog": { "confirm": "确认",