diff --git a/.agents/skills/comment-automation/references/channels.md b/.agents/skills/comment-automation/references/channels.md
index 10b9fa2b82..c874640c34 100644
--- a/.agents/skills/comment-automation/references/channels.md
+++ b/.agents/skills/comment-automation/references/channels.md
@@ -16,6 +16,7 @@
| `onlyCommentsWithImage` reply filter (`commentAutomationChannelSupportsImageFilter`) | ✅ | ❌ | ❌ | ✅ | ❌ |
| GIF hide (`commentAutomationChannelSupportsHideGif`) | ✅ | ❌ | ❌ | ✅ | ❌ |
| tag tracking / `mentions` filter | ✅ exact | ✅ text | ✅ text | ✅ text | ✅ text |
+ | post hashtag target (`post.type: "hashtags"`, caption read via `post-caption.ts`) | ✅ | ✅ | ✅ | ✅ | ⚠️ needs `video.list` |
Threads has no DM API at all; it hides only TOP-LEVEL replies (`manage_reply` — the worker
skips nested ones via `supportsHideForComment`) and
diff --git a/apps/builder/__tests__/comment-automation-post-hashtags.test.tsx b/apps/builder/__tests__/comment-automation-post-hashtags.test.tsx
new file mode 100644
index 0000000000..aed35b787c
--- /dev/null
+++ b/apps/builder/__tests__/comment-automation-post-hashtags.test.tsx
@@ -0,0 +1,113 @@
+import { act } from "react"
+import { createRoot } from "react-dom/client"
+import { describe, expect, test, vi } from "vitest"
+import { toChannelPostTarget } from "../src/features/shared/comment-automation/lib/channel-post-target"
+import { refinePostHashtags } from "../src/features/shared/comment-automation/lib/post-hashtags-validation"
+import { useClearPostValueOnHashtagsSwitch } from "../src/features/shared/comment-automation/use-clear-post-value-on-hashtags-switch"
+import {
+ createThreadsCommentRequest,
+ threadsCommentValidationKeys,
+} from "../src/features/threads-comments/schema/action"
+
+const threadsPayload = (post: { type: string; value: string[] }) => ({
+ name: "Auto reply",
+ post,
+ publicReply: { type: "none", value: null },
+ includeKeywords: { type: "all", value: [] },
+ excludeKeywords: [],
+ options: {
+ replyToNewContactsOnly: false,
+ replyOncePerUserPerPost: false,
+ replyToUsersWhoCommentedOnOtherPosts: true,
+ ignoreCommentReplies: true,
+ },
+ replyAfter: { type: "immediately", value: 0 },
+})
+
+describe("toChannelPostTarget", () => {
+ test("keeps a hashtags target and its list", () => {
+ expect(toChannelPostTarget({ type: "hashtags", value: ["vip"] })).toEqual({
+ type: "hashtags",
+ value: ["vip"],
+ })
+ })
+
+ test("reads a Meta-only type as all", () => {
+ expect(toChannelPostTarget({ type: "reels", value: [] })).toEqual({
+ type: "all",
+ value: [],
+ })
+ })
+})
+
+describe("threads hashtags target", () => {
+ test("accepts a hashtag list", () => {
+ const parsed = createThreadsCommentRequest.parse(
+ threadsPayload({ type: "hashtags", value: ["vip"] }),
+ )
+ expect(parsed.post).toEqual({ type: "hashtags", value: ["vip"] })
+ })
+
+ test("rejects an empty hashtag list", () => {
+ expect(() =>
+ createThreadsCommentRequest.parse(
+ threadsPayload({ type: "hashtags", value: [] }),
+ ),
+ ).toThrow(threadsCommentValidationKeys.hashtagsRequired)
+ })
+})
+
+describe("refinePostHashtags", () => {
+ test("flags an empty hashtags target on post.value", () => {
+ const addIssue = vi.fn()
+ refinePostHashtags("required")({ post: { type: "hashtags", value: [] } }, {
+ addIssue,
+ } as never)
+ expect(addIssue).toHaveBeenCalledWith(
+ expect.objectContaining({ path: ["post", "value"], message: "required" }),
+ )
+ })
+
+ test("ignores every other target", () => {
+ const addIssue = vi.fn()
+ refinePostHashtags("required")({ post: { type: "postIds", value: [] } }, {
+ addIssue,
+ } as never)
+ expect(addIssue).not.toHaveBeenCalled()
+ })
+})
+
+function Probe({ type, clear }: { type: string; clear: () => void }) {
+ useClearPostValueOnHashtagsSwitch(type, clear)
+ return null
+}
+
+/** Renders the hook through each post type in turn. */
+function renderTypes(types: string[], clear: () => void) {
+ const container = document.createElement("div")
+ const root = createRoot(container)
+ for (const type of types) {
+ act(() => root.render())
+ }
+ act(() => root.unmount())
+}
+
+describe("useClearPostValueOnHashtagsSwitch", () => {
+ test("never clears on the first render, so an edit keeps its list", () => {
+ const clear = vi.fn()
+ renderTypes(["hashtags"], clear)
+ expect(clear).not.toHaveBeenCalled()
+ })
+
+ test("clears when switching between post ids and hashtags", () => {
+ const clear = vi.fn()
+ renderTypes(["postIds", "hashtags", "postIds"], clear)
+ expect(clear).toHaveBeenCalledTimes(2)
+ })
+
+ test("keeps the list on a switch that does not involve hashtags", () => {
+ const clear = vi.fn()
+ renderTypes(["postIds", "all"], clear)
+ expect(clear).not.toHaveBeenCalled()
+ })
+})
diff --git a/apps/builder/messages/ar.json b/apps/builder/messages/ar.json
index d788bd81a4..b2be74f4e6 100644
--- a/apps/builder/messages/ar.json
+++ b/apps/builder/messages/ar.json
@@ -781,7 +781,9 @@
"engagedOnOtherPost": "تفاعل مسبقًا على منشور آخر",
"mentionCountNotMatched": "عدد الإشارات غير مطابق",
"noImageAttachment": "لا توجد صورة مرفقة",
- "moderated": "تم إخفاؤه أو حذفه بواسطة الإشراف"
+ "moderated": "تم إخفاؤه أو حذفه بواسطة الإشراف",
+ "postHashtagNotMatched": "المنشور لا يحتوي على وسم مطابق",
+ "postCaptionUnavailable": "تعذّرت قراءة نص المنشور"
},
"replyTo": {
"mentions": "التعليقات التي تحتوي على عدد كافٍ من الإشارات",
@@ -903,6 +905,15 @@
"previous": "السابق",
"next": "التالي",
"page": "الصفحة {page} من {pageCount}"
+ },
+ "postType": {
+ "hashtags": "المنشورات التي تحتوي على وسوم"
+ },
+ "postHashtags": {
+ "label": "الوسوم",
+ "description": "الرد فقط على المنشورات التي يحتوي نصها على وسم واحد على الأقل من هذه الوسوم. اكتب الوسم واضغط Enter. يتم التعرف على الوسم المضاف إلى منشور لاحقًا خلال 10 دقائق تقريبًا.",
+ "placeholder": "مثال: automation",
+ "required": "أضف وسمًا واحدًا على الأقل."
}
},
"condition": {
@@ -7830,7 +7841,8 @@
"delayMustBeZero": "Delay value must be zero for the selected timing option.",
"atLeastOneFieldRequired": "At least one field is required.",
"replyTextRequired": "أدخل رسالة رد واحدة على الأقل.",
- "hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword."
+ "hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword.",
+ "hashtagsRequired": "أضف وسمًا واحدًا على الأقل."
},
"hideCommentsDescription": "يمكن إخفاء الردود المباشرة على منشوراتك فقط.",
"hideComments": {
@@ -7946,13 +7958,18 @@
"delayMustBeZero": "Delay value must be zero for the selected timing option.",
"hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword.",
"atLeastOneFieldRequired": "At least one field is required.",
- "replyTextRequired": "أدخل رسالة رد واحدة على الأقل."
+ "replyTextRequired": "أدخل رسالة رد واحدة على الأقل.",
+ "hashtagsRequired": "أضف وسمًا واحدًا على الأقل."
},
"privateReply": "Private reply (Comment-to-Message)",
"privateReplyDescription": "Send a direct message to the commenter. TikTok only allows this for comments it flags as high intent, so it will not fire for every matching comment.",
"privateReplyMessage": "Private reply message",
"privateReplyHighIntentTitle": "TikTok decides which comments can be messaged",
- "privateReplyHighIntentNotice": "Comment-to-Message must be enabled on the connected TikTok account, and the account must be a Business Account registered in Vietnam, Indonesia or Thailand. TikTok sends the direct message only for first-level comments it flags as high intent, within 48 hours, once per comment, and not if the commenter already messaged you in the past 24 hours."
+ "privateReplyHighIntentNotice": "Comment-to-Message must be enabled on the connected TikTok account, and the account must be a Business Account registered in Vietnam, Indonesia or Thailand. TikTok sends the direct message only for first-level comments it flags as high intent, within 48 hours, once per comment, and not if the commenter already messaged you in the past 24 hours.",
+ "postHashtags": {
+ "reconnectRequired": "لا يمكن لحساب TikTok هذا قراءة أوصاف الفيديو بعد، لذلك سيتم تخطي كل التعليقات. أعد ربط الحساب من الإعدادات ← القنوات ← TikTok للسماح بذلك.",
+ "someAccountsReconnectRequired": "بعض حسابات TikTok لا يمكنها قراءة أوصاف الفيديو بعد، لذلك سيتم تخطي تعليقاتها. أعد ربطها من الإعدادات ← القنوات ← TikTok."
+ }
},
"commentAutomationMissedComments": {
"action": "معالجة التعليقات الفائتة",
diff --git a/apps/builder/messages/az.json b/apps/builder/messages/az.json
index 61564ddc72..af1e869848 100644
--- a/apps/builder/messages/az.json
+++ b/apps/builder/messages/az.json
@@ -823,7 +823,9 @@
"engagedOnOtherPost": "Başqa paylaşımla artıq qarşılıqlı əlaqə qurulub",
"mentionCountNotMatched": "Etiketlənən şəxslərin sayı uyğun gəlmədi",
"noImageAttachment": "Şəkil əlavə edilməyib",
- "moderated": "Moderasiya tərəfindən gizlədildi və ya silindi"
+ "moderated": "Moderasiya tərəfindən gizlədildi və ya silindi",
+ "postHashtagNotMatched": "Paylaşımda uyğun heşteq yoxdur",
+ "postCaptionUnavailable": "Paylaşımın mətni oxunmadı"
},
"replyTo": {
"mentions": "Kifayət qədər şəxsin etiketləndiyi şərhlər",
@@ -945,6 +947,15 @@
"previous": "Əvvəlki",
"next": "Növbəti",
"page": "Səhifə {page} / {pageCount}"
+ },
+ "postType": {
+ "hashtags": "Heşteqli paylaşımlar"
+ },
+ "postHashtags": {
+ "label": "Heşteqlər",
+ "description": "Yalnız mətnində bu heşteqlərdən ən azı biri olan paylaşımlara cavab verin. Heşteqi yazıb Enter düyməsini basın. Paylaşıma sonradan əlavə edilən heşteq təxminən 10 dəqiqə ərzində tanınır.",
+ "placeholder": "məs. automation",
+ "required": "Ən azı bir heşteq əlavə edin."
}
},
"condition": {
@@ -7534,7 +7545,8 @@
"delayMustBeZero": "Seçilmiş vaxt seçimi üçün gecikmə dəyəri sıfır olmalıdır.",
"atLeastOneFieldRequired": "Ən azı bir sahə məcburidir.",
"replyTextRequired": "Ən azı bir cavab mesajı daxil edin.",
- "hideKeywordsRequired": "Şərhləri açar sözə görə gizlətmək üçün ən azı bir açar söz daxil edin."
+ "hideKeywordsRequired": "Şərhləri açar sözə görə gizlətmək üçün ən azı bir açar söz daxil edin.",
+ "hashtagsRequired": "Ən azı bir heşteq əlavə edin."
},
"hideCommentsDescription": "Yalnız paylaşımlarınıza birbaşa verilən cavablar gizlədilə bilər.",
"hideComments": {
@@ -7650,13 +7662,18 @@
"delayMustBeZero": "Seçilmiş vaxt seçimi üçün gecikmə dəyəri sıfır olmalıdır.",
"hideKeywordsRequired": "Şərhləri açar sözə görə gizlətmək üçün ən azı bir açar söz daxil edin.",
"atLeastOneFieldRequired": "Ən azı bir sahə doldurulmalıdır.",
- "replyTextRequired": "Ən azı bir cavab mesajı daxil edin."
+ "replyTextRequired": "Ən azı bir cavab mesajı daxil edin.",
+ "hashtagsRequired": "Ən azı bir heşteq əlavə edin."
},
"privateReply": "Şəxsi cavab (şərhdən mesaja)",
"privateReplyDescription": "Şərh müəllifinə birbaşa mesaj göndərin. TikTok buna yalnız yüksək maraq ifadə etdiyini müəyyənləşdirdiyi şərhlər üçün icazə verir, buna görə hər uyğun şərh üçün mesaj göndərilməyəcək.",
"privateReplyMessage": "Şəxsi cavab mesajı",
"privateReplyHighIntentTitle": "Hansı şərhlərə mesaj göndərilə biləcəyini TikTok müəyyən edir",
- "privateReplyHighIntentNotice": "Qoşulmuş TikTok hesabında şərhdən mesaja funksiyası aktiv olmalı və hesab Vyetnam, İndoneziya və ya Taylandda qeydiyyatdan keçmiş biznes hesabı olmalıdır. TikTok birbaşa mesajı yalnız yüksək maraq ifadə etdiyini müəyyənləşdirdiyi, videoya birbaşa yazılmış şərhlər üçün, 48 saat ərzində və hər şərhə bir dəfə göndərir. Şərh müəllifi son 24 saat ərzində sizə artıq mesaj göndəribsə, mesaj göndərilmir."
+ "privateReplyHighIntentNotice": "Qoşulmuş TikTok hesabında şərhdən mesaja funksiyası aktiv olmalı və hesab Vyetnam, İndoneziya və ya Taylandda qeydiyyatdan keçmiş biznes hesabı olmalıdır. TikTok birbaşa mesajı yalnız yüksək maraq ifadə etdiyini müəyyənləşdirdiyi, videoya birbaşa yazılmış şərhlər üçün, 48 saat ərzində və hər şərhə bir dəfə göndərir. Şərh müəllifi son 24 saat ərzində sizə artıq mesaj göndəribsə, mesaj göndərilmir.",
+ "postHashtags": {
+ "reconnectRequired": "Bu TikTok hesabı hələ video mətnlərini oxuya bilmir, buna görə bütün şərhlər ötürüləcək. İcazə vermək üçün hesabı Parametrlər → Kanallar → TikTok bölməsində yenidən qoşun.",
+ "someAccountsReconnectRequired": "Bəzi TikTok hesablarınız hələ video mətnlərini oxuya bilmir, buna görə onların şərhləri ötürüləcək. Onları Parametrlər → Kanallar → TikTok bölməsində yenidən qoşun."
+ }
},
"commentAutomationMissedComments": {
"action": "Buraxılmış şərhləri emal et",
diff --git a/apps/builder/messages/da.json b/apps/builder/messages/da.json
index 79dbdd92ad..6740a4f732 100644
--- a/apps/builder/messages/da.json
+++ b/apps/builder/messages/da.json
@@ -781,7 +781,9 @@
"engagedOnOtherPost": "Har allerede interageret på et andet opslag",
"mentionCountNotMatched": "Antal omtaler matchede ikke",
"noImageAttachment": "Intet billede vedhæftet",
- "moderated": "Skjult eller slettet af moderering"
+ "moderated": "Skjult eller slettet af moderering",
+ "postHashtagNotMatched": "Opslaget har intet matchende hashtag",
+ "postCaptionUnavailable": "Opslagets tekst kunne ikke læses"
},
"replyTo": {
"mentions": "Kommentarer med nok omtaler",
@@ -903,6 +905,15 @@
"previous": "Forrige",
"next": "Næste",
"page": "Side {page} af {pageCount}"
+ },
+ "postType": {
+ "hashtags": "Opslag med hashtags"
+ },
+ "postHashtags": {
+ "label": "Hashtags",
+ "description": "Svar kun på opslag, hvis tekst indeholder mindst ét af disse hashtags. Skriv et hashtag, og tryk på Enter. Et hashtag, der tilføjes et opslag senere, registreres inden for ca. 10 minutter.",
+ "placeholder": "f.eks. automation",
+ "required": "Tilføj mindst ét hashtag."
}
},
"condition": {
@@ -6800,7 +6811,8 @@
"delayMustBeZero": "Delay value must be zero for the selected timing option.",
"atLeastOneFieldRequired": "At least one field is required.",
"replyTextRequired": "Angiv mindst én svarbesked.",
- "hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword."
+ "hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword.",
+ "hashtagsRequired": "Tilføj mindst ét hashtag."
},
"hideCommentsDescription": "Kun svar på øverste niveau til dine opslag kan skjules.",
"hideComments": {
@@ -6916,13 +6928,18 @@
"delayMustBeZero": "Delay value must be zero for the selected timing option.",
"hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword.",
"atLeastOneFieldRequired": "At least one field is required.",
- "replyTextRequired": "Angiv mindst én svarbesked."
+ "replyTextRequired": "Angiv mindst én svarbesked.",
+ "hashtagsRequired": "Tilføj mindst ét hashtag."
},
"privateReply": "Private reply (Comment-to-Message)",
"privateReplyDescription": "Send a direct message to the commenter. TikTok only allows this for comments it flags as high intent, so it will not fire for every matching comment.",
"privateReplyMessage": "Private reply message",
"privateReplyHighIntentTitle": "TikTok decides which comments can be messaged",
- "privateReplyHighIntentNotice": "Comment-to-Message must be enabled on the connected TikTok account, and the account must be a Business Account registered in Vietnam, Indonesia or Thailand. TikTok sends the direct message only for first-level comments it flags as high intent, within 48 hours, once per comment, and not if the commenter already messaged you in the past 24 hours."
+ "privateReplyHighIntentNotice": "Comment-to-Message must be enabled on the connected TikTok account, and the account must be a Business Account registered in Vietnam, Indonesia or Thailand. TikTok sends the direct message only for first-level comments it flags as high intent, within 48 hours, once per comment, and not if the commenter already messaged you in the past 24 hours.",
+ "postHashtags": {
+ "reconnectRequired": "Denne TikTok-konto kan endnu ikke læse videotekster, så alle kommentarer springes over. Forbind kontoen igen under Indstillinger → Kanaler → TikTok for at tillade det.",
+ "someAccountsReconnectRequired": "Nogle af dine TikTok-konti kan endnu ikke læse videotekster, så deres kommentarer springes over. Forbind dem igen under Indstillinger → Kanaler → TikTok."
+ }
},
"commentAutomationMissedComments": {
"action": "Behandl oversete kommentarer",
diff --git a/apps/builder/messages/de.json b/apps/builder/messages/de.json
index 869709e7b8..9482e69875 100644
--- a/apps/builder/messages/de.json
+++ b/apps/builder/messages/de.json
@@ -781,7 +781,9 @@
"engagedOnOtherPost": "Bereits bei einem anderen Beitrag interagiert",
"mentionCountNotMatched": "Anzahl der Erwähnungen stimmte nicht",
"noImageAttachment": "Kein Foto angehängt",
- "moderated": "Durch Moderation ausgeblendet oder gelöscht"
+ "moderated": "Durch Moderation ausgeblendet oder gelöscht",
+ "postHashtagNotMatched": "Beitrag hat keinen passenden Hashtag",
+ "postCaptionUnavailable": "Beitragstext konnte nicht gelesen werden"
},
"replyTo": {
"mentions": "Kommentare mit genügend Erwähnungen",
@@ -903,6 +905,15 @@
"previous": "Zurück",
"next": "Weiter",
"page": "Seite {page} von {pageCount}"
+ },
+ "postType": {
+ "hashtags": "Beiträge mit Hashtags"
+ },
+ "postHashtags": {
+ "label": "Hashtags",
+ "description": "Nur auf Beiträge antworten, deren Text mindestens einen dieser Hashtags enthält. Hashtag eingeben und Enter drücken. Ein später zu einem Beitrag hinzugefügter Hashtag wird innerhalb von etwa 10 Minuten erkannt.",
+ "placeholder": "z. B. automation",
+ "required": "Füge mindestens einen Hashtag hinzu."
}
},
"condition": {
@@ -6800,7 +6811,8 @@
"delayMustBeZero": "Delay value must be zero for the selected timing option.",
"atLeastOneFieldRequired": "At least one field is required.",
"replyTextRequired": "Gib mindestens eine Antwortnachricht ein.",
- "hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword."
+ "hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword.",
+ "hashtagsRequired": "Füge mindestens einen Hashtag hinzu."
},
"hideCommentsDescription": "Nur direkte Antworten auf deine Beiträge können ausgeblendet werden.",
"hideComments": {
@@ -6916,13 +6928,18 @@
"delayMustBeZero": "Delay value must be zero for the selected timing option.",
"hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword.",
"atLeastOneFieldRequired": "At least one field is required.",
- "replyTextRequired": "Gib mindestens eine Antwortnachricht ein."
+ "replyTextRequired": "Gib mindestens eine Antwortnachricht ein.",
+ "hashtagsRequired": "Füge mindestens einen Hashtag hinzu."
},
"privateReply": "Private reply (Comment-to-Message)",
"privateReplyDescription": "Send a direct message to the commenter. TikTok only allows this for comments it flags as high intent, so it will not fire for every matching comment.",
"privateReplyMessage": "Private reply message",
"privateReplyHighIntentTitle": "TikTok decides which comments can be messaged",
- "privateReplyHighIntentNotice": "Comment-to-Message must be enabled on the connected TikTok account, and the account must be a Business Account registered in Vietnam, Indonesia or Thailand. TikTok sends the direct message only for first-level comments it flags as high intent, within 48 hours, once per comment, and not if the commenter already messaged you in the past 24 hours."
+ "privateReplyHighIntentNotice": "Comment-to-Message must be enabled on the connected TikTok account, and the account must be a Business Account registered in Vietnam, Indonesia or Thailand. TikTok sends the direct message only for first-level comments it flags as high intent, within 48 hours, once per comment, and not if the commenter already messaged you in the past 24 hours.",
+ "postHashtags": {
+ "reconnectRequired": "Dieses TikTok-Konto kann Videobeschreibungen noch nicht lesen, daher werden alle Kommentare übersprungen. Verbinde das Konto unter Einstellungen → Kanäle → TikTok neu, um es zu erlauben.",
+ "someAccountsReconnectRequired": "Einige deiner TikTok-Konten können Videobeschreibungen noch nicht lesen, daher werden ihre Kommentare übersprungen. Verbinde sie unter Einstellungen → Kanäle → TikTok neu."
+ }
},
"commentAutomationMissedComments": {
"action": "Verpasste Kommentare verarbeiten",
diff --git a/apps/builder/messages/en.json b/apps/builder/messages/en.json
index 00648cb76c..4943db3a87 100644
--- a/apps/builder/messages/en.json
+++ b/apps/builder/messages/en.json
@@ -823,7 +823,9 @@
"engagedOnOtherPost": "Already engaged on another post",
"mentionCountNotMatched": "Mention count did not match",
"noImageAttachment": "No photo attached",
- "moderated": "Hidden or deleted by moderation"
+ "moderated": "Hidden or deleted by moderation",
+ "postHashtagNotMatched": "Post has no matching hashtag",
+ "postCaptionUnavailable": "Couldn't read the post caption"
},
"replyTo": {
"mentions": "Comments when enough mentions",
@@ -945,6 +947,15 @@
"previous": "Previous",
"next": "Next",
"page": "Page {page} of {pageCount}"
+ },
+ "postType": {
+ "hashtags": "Posts with hashtags"
+ },
+ "postHashtags": {
+ "label": "Hashtags",
+ "description": "Reply only on posts whose caption contains at least one of these hashtags. Type a hashtag and press Enter. A hashtag added to a post later is picked up within about 10 minutes.",
+ "placeholder": "e.g. automation",
+ "required": "Add at least one hashtag."
}
},
"condition": {
@@ -7534,7 +7545,8 @@
"delayMustBeZero": "Delay value must be zero for the selected timing option.",
"atLeastOneFieldRequired": "At least one field is required.",
"replyTextRequired": "Enter at least one reply message.",
- "hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword."
+ "hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword.",
+ "hashtagsRequired": "Add at least one hashtag."
},
"hideCommentsDescription": "Only top-level replies to your posts can be hidden.",
"hideComments": {
@@ -7650,13 +7662,18 @@
"delayMustBeZero": "Delay value must be zero for the selected timing option.",
"hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword.",
"atLeastOneFieldRequired": "At least one field is required.",
- "replyTextRequired": "Enter at least one reply message."
+ "replyTextRequired": "Enter at least one reply message.",
+ "hashtagsRequired": "Add at least one hashtag."
},
"privateReply": "Private reply (Comment-to-Message)",
"privateReplyDescription": "Send a direct message to the commenter. TikTok only allows this for comments it flags as high intent, so it will not fire for every matching comment.",
"privateReplyMessage": "Private reply message",
"privateReplyHighIntentTitle": "TikTok decides which comments can be messaged",
- "privateReplyHighIntentNotice": "Comment-to-Message must be enabled on the connected TikTok account, and the account must be a Business Account registered in Vietnam, Indonesia or Thailand. TikTok sends the direct message only for first-level comments it flags as high intent, within 48 hours, once per comment, and not if the commenter already messaged you in the past 24 hours."
+ "privateReplyHighIntentNotice": "Comment-to-Message must be enabled on the connected TikTok account, and the account must be a Business Account registered in Vietnam, Indonesia or Thailand. TikTok sends the direct message only for first-level comments it flags as high intent, within 48 hours, once per comment, and not if the commenter already messaged you in the past 24 hours.",
+ "postHashtags": {
+ "reconnectRequired": "This TikTok account can't read video captions yet, so every comment will be skipped. Reconnect the account in Settings → Channels → TikTok to allow it.",
+ "someAccountsReconnectRequired": "Some of your TikTok accounts can't read video captions yet, so their comments will be skipped. Reconnect them in Settings → Channels → TikTok."
+ }
},
"commentAutomationMissedComments": {
"action": "Process missed comments",
diff --git a/apps/builder/messages/es.json b/apps/builder/messages/es.json
index 9d28ec6031..33bb9ae032 100644
--- a/apps/builder/messages/es.json
+++ b/apps/builder/messages/es.json
@@ -781,7 +781,9 @@
"engagedOnOtherPost": "Ya interactuó en otra publicación",
"mentionCountNotMatched": "El número de menciones no coincidió",
"noImageAttachment": "Sin foto adjunta",
- "moderated": "Oculto o eliminado por moderación"
+ "moderated": "Oculto o eliminado por moderación",
+ "postHashtagNotMatched": "La publicación no tiene un hashtag coincidente",
+ "postCaptionUnavailable": "No se pudo leer el texto de la publicación"
},
"replyTo": {
"mentions": "Comentarios con suficientes menciones",
@@ -903,6 +905,15 @@
"previous": "Anterior",
"next": "Siguiente",
"page": "Página {page} de {pageCount}"
+ },
+ "postType": {
+ "hashtags": "Publicaciones con hashtags"
+ },
+ "postHashtags": {
+ "label": "Hashtags",
+ "description": "Responder solo en publicaciones cuyo texto contenga al menos uno de estos hashtags. Escribe un hashtag y pulsa Enter. Un hashtag añadido después a una publicación se detecta en unos 10 minutos.",
+ "placeholder": "p. ej., automation",
+ "required": "Añade al menos un hashtag."
}
},
"condition": {
@@ -6800,7 +6811,8 @@
"delayMustBeZero": "Delay value must be zero for the selected timing option.",
"atLeastOneFieldRequired": "At least one field is required.",
"replyTextRequired": "Introduce al menos un mensaje de respuesta.",
- "hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword."
+ "hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword.",
+ "hashtagsRequired": "Añade al menos un hashtag."
},
"hideCommentsDescription": "Solo se pueden ocultar las respuestas de primer nivel a tus publicaciones.",
"hideComments": {
@@ -6916,13 +6928,18 @@
"delayMustBeZero": "Delay value must be zero for the selected timing option.",
"hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword.",
"atLeastOneFieldRequired": "At least one field is required.",
- "replyTextRequired": "Introduce al menos un mensaje de respuesta."
+ "replyTextRequired": "Introduce al menos un mensaje de respuesta.",
+ "hashtagsRequired": "Añade al menos un hashtag."
},
"privateReply": "Private reply (Comment-to-Message)",
"privateReplyDescription": "Send a direct message to the commenter. TikTok only allows this for comments it flags as high intent, so it will not fire for every matching comment.",
"privateReplyMessage": "Private reply message",
"privateReplyHighIntentTitle": "TikTok decides which comments can be messaged",
- "privateReplyHighIntentNotice": "Comment-to-Message must be enabled on the connected TikTok account, and the account must be a Business Account registered in Vietnam, Indonesia or Thailand. TikTok sends the direct message only for first-level comments it flags as high intent, within 48 hours, once per comment, and not if the commenter already messaged you in the past 24 hours."
+ "privateReplyHighIntentNotice": "Comment-to-Message must be enabled on the connected TikTok account, and the account must be a Business Account registered in Vietnam, Indonesia or Thailand. TikTok sends the direct message only for first-level comments it flags as high intent, within 48 hours, once per comment, and not if the commenter already messaged you in the past 24 hours.",
+ "postHashtags": {
+ "reconnectRequired": "Esta cuenta de TikTok aún no puede leer las descripciones de los videos, así que se omitirán todos los comentarios. Vuelve a conectar la cuenta en Configuración → Canales → TikTok para permitirlo.",
+ "someAccountsReconnectRequired": "Algunas de tus cuentas de TikTok aún no pueden leer las descripciones de los videos, así que se omitirán sus comentarios. Vuelve a conectarlas en Configuración → Canales → TikTok."
+ }
},
"commentAutomationMissedComments": {
"action": "Procesar comentarios omitidos",
diff --git a/apps/builder/messages/fi.json b/apps/builder/messages/fi.json
index 8338e0d0ff..1b5604f8d8 100644
--- a/apps/builder/messages/fi.json
+++ b/apps/builder/messages/fi.json
@@ -781,7 +781,9 @@
"engagedOnOtherPost": "Jo vuorovaikutuksessa toisessa julkaisussa",
"mentionCountNotMatched": "Mainintojen määrä ei täsmännyt",
"noImageAttachment": "Ei liitettyä kuvaa",
- "moderated": "Moderointi piilotti tai poisti"
+ "moderated": "Moderointi piilotti tai poisti",
+ "postHashtagNotMatched": "Julkaisussa ei ole vastaavaa aihetunnistetta",
+ "postCaptionUnavailable": "Julkaisun tekstiä ei voitu lukea"
},
"replyTo": {
"mentions": "Kommentit, joissa on tarpeeksi mainintoja",
@@ -903,6 +905,15 @@
"previous": "Edellinen",
"next": "Seuraava",
"page": "Sivu {page}/{pageCount}"
+ },
+ "postType": {
+ "hashtags": "Julkaisut, joissa on aihetunnisteita"
+ },
+ "postHashtags": {
+ "label": "Aihetunnisteet",
+ "description": "Vastaa vain julkaisuihin, joiden tekstissä on vähintään yksi näistä aihetunnisteista. Kirjoita aihetunniste ja paina Enter. Julkaisuun myöhemmin lisätty aihetunniste tunnistetaan noin 10 minuutin kuluessa.",
+ "placeholder": "esim. automation",
+ "required": "Lisää vähintään yksi aihetunniste."
}
},
"condition": {
@@ -6800,7 +6811,8 @@
"delayMustBeZero": "Delay value must be zero for the selected timing option.",
"atLeastOneFieldRequired": "At least one field is required.",
"replyTextRequired": "Anna vähintään yksi vastausviesti.",
- "hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword."
+ "hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword.",
+ "hashtagsRequired": "Lisää vähintään yksi aihetunniste."
},
"hideCommentsDescription": "Vain julkaisujesi ylimmän tason vastaukset voidaan piilottaa.",
"hideComments": {
@@ -6916,13 +6928,18 @@
"delayMustBeZero": "Delay value must be zero for the selected timing option.",
"hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword.",
"atLeastOneFieldRequired": "At least one field is required.",
- "replyTextRequired": "Anna vähintään yksi vastausviesti."
+ "replyTextRequired": "Anna vähintään yksi vastausviesti.",
+ "hashtagsRequired": "Lisää vähintään yksi aihetunniste."
},
"privateReply": "Private reply (Comment-to-Message)",
"privateReplyDescription": "Send a direct message to the commenter. TikTok only allows this for comments it flags as high intent, so it will not fire for every matching comment.",
"privateReplyMessage": "Private reply message",
"privateReplyHighIntentTitle": "TikTok decides which comments can be messaged",
- "privateReplyHighIntentNotice": "Comment-to-Message must be enabled on the connected TikTok account, and the account must be a Business Account registered in Vietnam, Indonesia or Thailand. TikTok sends the direct message only for first-level comments it flags as high intent, within 48 hours, once per comment, and not if the commenter already messaged you in the past 24 hours."
+ "privateReplyHighIntentNotice": "Comment-to-Message must be enabled on the connected TikTok account, and the account must be a Business Account registered in Vietnam, Indonesia or Thailand. TikTok sends the direct message only for first-level comments it flags as high intent, within 48 hours, once per comment, and not if the commenter already messaged you in the past 24 hours.",
+ "postHashtags": {
+ "reconnectRequired": "Tämä TikTok-tili ei vielä voi lukea videoiden kuvauksia, joten kaikki kommentit ohitetaan. Yhdistä tili uudelleen kohdassa Asetukset → Kanavat → TikTok salliaksesi sen.",
+ "someAccountsReconnectRequired": "Osa TikTok-tileistäsi ei vielä voi lukea videoiden kuvauksia, joten niiden kommentit ohitetaan. Yhdistä ne uudelleen kohdassa Asetukset → Kanavat → TikTok."
+ }
},
"commentAutomationMissedComments": {
"action": "Käsittele väliin jääneet kommentit",
diff --git a/apps/builder/messages/fr.json b/apps/builder/messages/fr.json
index 3715806e3f..e79545d81d 100644
--- a/apps/builder/messages/fr.json
+++ b/apps/builder/messages/fr.json
@@ -781,7 +781,9 @@
"engagedOnOtherPost": "A déjà interagi sur une autre publication",
"mentionCountNotMatched": "Le nombre de mentions ne correspondait pas",
"noImageAttachment": "Aucune photo jointe",
- "moderated": "Masqué ou supprimé par la modération"
+ "moderated": "Masqué ou supprimé par la modération",
+ "postHashtagNotMatched": "La publication n'a aucun hashtag correspondant",
+ "postCaptionUnavailable": "Impossible de lire le texte de la publication"
},
"replyTo": {
"mentions": "Commentaires avec suffisamment de mentions",
@@ -903,6 +905,15 @@
"previous": "Précédent",
"next": "Suivant",
"page": "Page {page} sur {pageCount}"
+ },
+ "postType": {
+ "hashtags": "Publications avec hashtags"
+ },
+ "postHashtags": {
+ "label": "Hashtags",
+ "description": "Répondre uniquement aux publications dont le texte contient au moins un de ces hashtags. Saisissez un hashtag puis appuyez sur Entrée. Un hashtag ajouté plus tard à une publication est pris en compte en 10 minutes environ.",
+ "placeholder": "ex. : automation",
+ "required": "Ajoutez au moins un hashtag."
}
},
"condition": {
@@ -6800,7 +6811,8 @@
"delayMustBeZero": "Delay value must be zero for the selected timing option.",
"atLeastOneFieldRequired": "At least one field is required.",
"replyTextRequired": "Saisissez au moins un message de réponse.",
- "hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword."
+ "hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword.",
+ "hashtagsRequired": "Ajoutez au moins un hashtag."
},
"hideCommentsDescription": "Seules les réponses de premier niveau à vos publications peuvent être masquées.",
"hideComments": {
@@ -6916,13 +6928,18 @@
"delayMustBeZero": "Delay value must be zero for the selected timing option.",
"hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword.",
"atLeastOneFieldRequired": "At least one field is required.",
- "replyTextRequired": "Saisissez au moins un message de réponse."
+ "replyTextRequired": "Saisissez au moins un message de réponse.",
+ "hashtagsRequired": "Ajoutez au moins un hashtag."
},
"privateReply": "Private reply (Comment-to-Message)",
"privateReplyDescription": "Send a direct message to the commenter. TikTok only allows this for comments it flags as high intent, so it will not fire for every matching comment.",
"privateReplyMessage": "Private reply message",
"privateReplyHighIntentTitle": "TikTok decides which comments can be messaged",
- "privateReplyHighIntentNotice": "Comment-to-Message must be enabled on the connected TikTok account, and the account must be a Business Account registered in Vietnam, Indonesia or Thailand. TikTok sends the direct message only for first-level comments it flags as high intent, within 48 hours, once per comment, and not if the commenter already messaged you in the past 24 hours."
+ "privateReplyHighIntentNotice": "Comment-to-Message must be enabled on the connected TikTok account, and the account must be a Business Account registered in Vietnam, Indonesia or Thailand. TikTok sends the direct message only for first-level comments it flags as high intent, within 48 hours, once per comment, and not if the commenter already messaged you in the past 24 hours.",
+ "postHashtags": {
+ "reconnectRequired": "Ce compte TikTok ne peut pas encore lire les descriptions des vidéos, donc tous les commentaires seront ignorés. Reconnectez le compte dans Paramètres → Canaux → TikTok pour l'autoriser.",
+ "someAccountsReconnectRequired": "Certains de vos comptes TikTok ne peuvent pas encore lire les descriptions des vidéos, donc leurs commentaires seront ignorés. Reconnectez-les dans Paramètres → Canaux → TikTok."
+ }
},
"commentAutomationMissedComments": {
"action": "Traiter les commentaires manqués",
diff --git a/apps/builder/messages/he.json b/apps/builder/messages/he.json
index b9173011ae..73bdb545da 100644
--- a/apps/builder/messages/he.json
+++ b/apps/builder/messages/he.json
@@ -4445,7 +4445,8 @@
"delayMustBeZero": "Delay value must be zero for the selected timing option.",
"atLeastOneFieldRequired": "At least one field is required.",
"replyTextRequired": "הזינו לפחות הודעת תגובה אחת.",
- "hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword."
+ "hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword.",
+ "hashtagsRequired": "הוסיפו לפחות האשטג אחד."
},
"hideCommentsDescription": "ניתן להסתיר רק תגובות ברמה העליונה לפוסטים שלכם.",
"hideComments": {
@@ -4561,13 +4562,18 @@
"delayMustBeZero": "Delay value must be zero for the selected timing option.",
"hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword.",
"atLeastOneFieldRequired": "At least one field is required.",
- "replyTextRequired": "הזינו לפחות הודעת תגובה אחת."
+ "replyTextRequired": "הזינו לפחות הודעת תגובה אחת.",
+ "hashtagsRequired": "הוסיפו לפחות האשטג אחד."
},
"privateReply": "Private reply (Comment-to-Message)",
"privateReplyDescription": "Send a direct message to the commenter. TikTok only allows this for comments it flags as high intent, so it will not fire for every matching comment.",
"privateReplyMessage": "Private reply message",
"privateReplyHighIntentTitle": "TikTok decides which comments can be messaged",
- "privateReplyHighIntentNotice": "Comment-to-Message must be enabled on the connected TikTok account, and the account must be a Business Account registered in Vietnam, Indonesia or Thailand. TikTok sends the direct message only for first-level comments it flags as high intent, within 48 hours, once per comment, and not if the commenter already messaged you in the past 24 hours."
+ "privateReplyHighIntentNotice": "Comment-to-Message must be enabled on the connected TikTok account, and the account must be a Business Account registered in Vietnam, Indonesia or Thailand. TikTok sends the direct message only for first-level comments it flags as high intent, within 48 hours, once per comment, and not if the commenter already messaged you in the past 24 hours.",
+ "postHashtags": {
+ "reconnectRequired": "חשבון TikTok זה עדיין לא יכול לקרוא תיאורי סרטונים, ולכן כל התגובות ידולגו. חברו מחדש את החשבון בהגדרות ← ערוצים ← TikTok כדי לאפשר זאת.",
+ "someAccountsReconnectRequired": "חלק מחשבונות ה-TikTok שלכם עדיין לא יכולים לקרוא תיאורי סרטונים, ולכן התגובות שלהם ידולגו. חברו אותם מחדש בהגדרות ← ערוצים ← TikTok."
+ }
},
"commentAutomationMissedComments": {
"action": "עיבוד תגובות שפוספסו",
@@ -7908,7 +7914,9 @@
"engagedOnOtherPost": "כבר היה מעורב בפוסט אחר",
"mentionCountNotMatched": "מספר האזכורים לא תאם",
"noImageAttachment": "לא צורפה תמונה",
- "moderated": "הוסתר או נמחק על ידי ניהול התוכן"
+ "moderated": "הוסתר או נמחק על ידי ניהול התוכן",
+ "postHashtagNotMatched": "בפוסט אין האשטג תואם",
+ "postCaptionUnavailable": "לא ניתן היה לקרוא את טקסט הפוסט"
},
"replyTo": {
"mentions": "תגובות עם מספיק אזכורים",
@@ -8030,6 +8038,15 @@
"previous": "הקודם",
"next": "הבא",
"page": "עמוד {page} מתוך {pageCount}"
+ },
+ "postType": {
+ "hashtags": "פוסטים עם האשטגים"
+ },
+ "postHashtags": {
+ "label": "האשטגים",
+ "description": "להגיב רק לפוסטים שהטקסט שלהם מכיל לפחות אחד מההאשטגים האלה. הקלידו האשטג ולחצו Enter. האשטג שנוסף לפוסט מאוחר יותר יזוהה תוך כ-10 דקות.",
+ "placeholder": "לדוגמה: automation",
+ "required": "הוסיפו לפחות האשטג אחד."
}
},
"condition": {
diff --git a/apps/builder/messages/id.json b/apps/builder/messages/id.json
index 66e11b8513..3994c9cdf0 100644
--- a/apps/builder/messages/id.json
+++ b/apps/builder/messages/id.json
@@ -781,7 +781,9 @@
"engagedOnOtherPost": "Sudah berinteraksi di postingan lain",
"mentionCountNotMatched": "Jumlah sebutan tidak cocok",
"noImageAttachment": "Tidak ada foto terlampir",
- "moderated": "Disembunyikan atau dihapus oleh moderasi"
+ "moderated": "Disembunyikan atau dihapus oleh moderasi",
+ "postHashtagNotMatched": "Postingan tidak memiliki hashtag yang cocok",
+ "postCaptionUnavailable": "Teks postingan tidak dapat dibaca"
},
"replyTo": {
"mentions": "Komentar dengan cukup sebutan",
@@ -903,6 +905,15 @@
"previous": "Sebelumnya",
"next": "Berikutnya",
"page": "Halaman {page} dari {pageCount}"
+ },
+ "postType": {
+ "hashtags": "Postingan dengan hashtag"
+ },
+ "postHashtags": {
+ "label": "Hashtag",
+ "description": "Balas hanya di postingan yang teksnya berisi setidaknya satu hashtag ini. Ketik hashtag lalu tekan Enter. Hashtag yang ditambahkan ke postingan belakangan akan terdeteksi dalam sekitar 10 menit.",
+ "placeholder": "mis. automation",
+ "required": "Tambahkan setidaknya satu hashtag."
}
},
"condition": {
@@ -6800,7 +6811,8 @@
"delayMustBeZero": "Delay value must be zero for the selected timing option.",
"atLeastOneFieldRequired": "At least one field is required.",
"replyTextRequired": "Masukkan setidaknya satu pesan balasan.",
- "hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword."
+ "hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword.",
+ "hashtagsRequired": "Tambahkan setidaknya satu hashtag."
},
"hideCommentsDescription": "Hanya balasan tingkat atas pada postingan Anda yang dapat disembunyikan.",
"hideComments": {
@@ -6916,13 +6928,18 @@
"delayMustBeZero": "Delay value must be zero for the selected timing option.",
"hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword.",
"atLeastOneFieldRequired": "At least one field is required.",
- "replyTextRequired": "Masukkan setidaknya satu pesan balasan."
+ "replyTextRequired": "Masukkan setidaknya satu pesan balasan.",
+ "hashtagsRequired": "Tambahkan setidaknya satu hashtag."
},
"privateReply": "Private reply (Comment-to-Message)",
"privateReplyDescription": "Send a direct message to the commenter. TikTok only allows this for comments it flags as high intent, so it will not fire for every matching comment.",
"privateReplyMessage": "Private reply message",
"privateReplyHighIntentTitle": "TikTok decides which comments can be messaged",
- "privateReplyHighIntentNotice": "Comment-to-Message must be enabled on the connected TikTok account, and the account must be a Business Account registered in Vietnam, Indonesia or Thailand. TikTok sends the direct message only for first-level comments it flags as high intent, within 48 hours, once per comment, and not if the commenter already messaged you in the past 24 hours."
+ "privateReplyHighIntentNotice": "Comment-to-Message must be enabled on the connected TikTok account, and the account must be a Business Account registered in Vietnam, Indonesia or Thailand. TikTok sends the direct message only for first-level comments it flags as high intent, within 48 hours, once per comment, and not if the commenter already messaged you in the past 24 hours.",
+ "postHashtags": {
+ "reconnectRequired": "Akun TikTok ini belum dapat membaca keterangan video, sehingga semua komentar akan dilewati. Hubungkan ulang akun di Pengaturan → Saluran → TikTok untuk mengizinkannya.",
+ "someAccountsReconnectRequired": "Beberapa akun TikTok Anda belum dapat membaca keterangan video, sehingga komentarnya akan dilewati. Hubungkan ulang di Pengaturan → Saluran → TikTok."
+ }
},
"commentAutomationMissedComments": {
"action": "Proses komentar yang terlewat",
diff --git a/apps/builder/messages/it.json b/apps/builder/messages/it.json
index 6bcb8026d0..42d4d3edf5 100644
--- a/apps/builder/messages/it.json
+++ b/apps/builder/messages/it.json
@@ -2459,7 +2459,9 @@
"engagedOnOtherPost": "Ha già interagito su un altro post",
"mentionCountNotMatched": "Il numero di menzioni non corrispondeva",
"noImageAttachment": "Nessuna foto allegata",
- "moderated": "Nascosto o eliminato dalla moderazione"
+ "moderated": "Nascosto o eliminato dalla moderazione",
+ "postHashtagNotMatched": "Il post non ha hashtag corrispondenti",
+ "postCaptionUnavailable": "Impossibile leggere il testo del post"
},
"replyTo": {
"mentions": "Commenti con abbastanza menzioni",
@@ -2581,6 +2583,15 @@
"previous": "Precedente",
"next": "Successivo",
"page": "Pagina {page} di {pageCount}"
+ },
+ "postType": {
+ "hashtags": "Post con hashtag"
+ },
+ "postHashtags": {
+ "label": "Hashtag",
+ "description": "Rispondi solo ai post il cui testo contiene almeno uno di questi hashtag. Digita un hashtag e premi Invio. Un hashtag aggiunto in seguito a un post viene rilevato entro circa 10 minuti.",
+ "placeholder": "es. automation",
+ "required": "Aggiungi almeno un hashtag."
}
},
"condition": {
@@ -6800,7 +6811,8 @@
"delayMustBeZero": "Delay value must be zero for the selected timing option.",
"atLeastOneFieldRequired": "At least one field is required.",
"replyTextRequired": "Inserisci almeno un messaggio di risposta.",
- "hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword."
+ "hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword.",
+ "hashtagsRequired": "Aggiungi almeno un hashtag."
},
"hideCommentsDescription": "Solo le risposte di primo livello ai tuoi post possono essere nascoste.",
"hideComments": {
@@ -6916,13 +6928,18 @@
"delayMustBeZero": "Delay value must be zero for the selected timing option.",
"hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword.",
"atLeastOneFieldRequired": "At least one field is required.",
- "replyTextRequired": "Inserisci almeno un messaggio di risposta."
+ "replyTextRequired": "Inserisci almeno un messaggio di risposta.",
+ "hashtagsRequired": "Aggiungi almeno un hashtag."
},
"privateReply": "Private reply (Comment-to-Message)",
"privateReplyDescription": "Send a direct message to the commenter. TikTok only allows this for comments it flags as high intent, so it will not fire for every matching comment.",
"privateReplyMessage": "Private reply message",
"privateReplyHighIntentTitle": "TikTok decides which comments can be messaged",
- "privateReplyHighIntentNotice": "Comment-to-Message must be enabled on the connected TikTok account, and the account must be a Business Account registered in Vietnam, Indonesia or Thailand. TikTok sends the direct message only for first-level comments it flags as high intent, within 48 hours, once per comment, and not if the commenter already messaged you in the past 24 hours."
+ "privateReplyHighIntentNotice": "Comment-to-Message must be enabled on the connected TikTok account, and the account must be a Business Account registered in Vietnam, Indonesia or Thailand. TikTok sends the direct message only for first-level comments it flags as high intent, within 48 hours, once per comment, and not if the commenter already messaged you in the past 24 hours.",
+ "postHashtags": {
+ "reconnectRequired": "Questo account TikTok non può ancora leggere le descrizioni dei video, quindi tutti i commenti verranno saltati. Ricollega l'account in Impostazioni → Canali → TikTok per consentirlo.",
+ "someAccountsReconnectRequired": "Alcuni dei tuoi account TikTok non possono ancora leggere le descrizioni dei video, quindi i loro commenti verranno saltati. Ricollegali in Impostazioni → Canali → TikTok."
+ }
},
"commentAutomationMissedComments": {
"action": "Elabora commenti persi",
diff --git a/apps/builder/messages/ja.json b/apps/builder/messages/ja.json
index 683934d6dd..d2aed540e1 100644
--- a/apps/builder/messages/ja.json
+++ b/apps/builder/messages/ja.json
@@ -781,7 +781,9 @@
"engagedOnOtherPost": "他の投稿で既に反応済み",
"mentionCountNotMatched": "メンション数が一致しませんでした",
"noImageAttachment": "写真が添付されていません",
- "moderated": "モデレーションにより非表示または削除されました"
+ "moderated": "モデレーションにより非表示または削除されました",
+ "postHashtagNotMatched": "投稿に一致するハッシュタグがありません",
+ "postCaptionUnavailable": "投稿の本文を読み取れませんでした"
},
"replyTo": {
"mentions": "十分なメンションがあるコメント",
@@ -903,6 +905,15 @@
"previous": "前へ",
"next": "次へ",
"page": "{page} / {pageCount} ページ"
+ },
+ "postType": {
+ "hashtags": "ハッシュタグ付きの投稿"
+ },
+ "postHashtags": {
+ "label": "ハッシュタグ",
+ "description": "本文にこれらのハッシュタグのいずれかを含む投稿にのみ返信します。ハッシュタグを入力して Enter を押してください。後から投稿に追加したハッシュタグは約10分以内に反映されます。",
+ "placeholder": "例: automation",
+ "required": "ハッシュタグを1つ以上追加してください。"
}
},
"condition": {
@@ -6777,7 +6788,8 @@
"delayMustBeZero": "Delay value must be zero for the selected timing option.",
"atLeastOneFieldRequired": "At least one field is required.",
"replyTextRequired": "返信メッセージを1件以上入力してください。",
- "hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword."
+ "hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword.",
+ "hashtagsRequired": "ハッシュタグを1つ以上追加してください。"
},
"hideCommentsDescription": "非表示にできるのは投稿への最上位の返信のみです。",
"hideComments": {
@@ -6893,13 +6905,18 @@
"delayMustBeZero": "Delay value must be zero for the selected timing option.",
"hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword.",
"atLeastOneFieldRequired": "At least one field is required.",
- "replyTextRequired": "返信メッセージを1件以上入力してください。"
+ "replyTextRequired": "返信メッセージを1件以上入力してください。",
+ "hashtagsRequired": "ハッシュタグを1つ以上追加してください。"
},
"privateReply": "Private reply (Comment-to-Message)",
"privateReplyDescription": "Send a direct message to the commenter. TikTok only allows this for comments it flags as high intent, so it will not fire for every matching comment.",
"privateReplyMessage": "Private reply message",
"privateReplyHighIntentTitle": "TikTok decides which comments can be messaged",
- "privateReplyHighIntentNotice": "Comment-to-Message must be enabled on the connected TikTok account, and the account must be a Business Account registered in Vietnam, Indonesia or Thailand. TikTok sends the direct message only for first-level comments it flags as high intent, within 48 hours, once per comment, and not if the commenter already messaged you in the past 24 hours."
+ "privateReplyHighIntentNotice": "Comment-to-Message must be enabled on the connected TikTok account, and the account must be a Business Account registered in Vietnam, Indonesia or Thailand. TikTok sends the direct message only for first-level comments it flags as high intent, within 48 hours, once per comment, and not if the commenter already messaged you in the past 24 hours.",
+ "postHashtags": {
+ "reconnectRequired": "このTikTokアカウントはまだ動画の説明文を読み取れないため、すべてのコメントがスキップされます。設定 → チャネル → TikTok でアカウントを再接続して許可してください。",
+ "someAccountsReconnectRequired": "一部のTikTokアカウントはまだ動画の説明文を読み取れないため、それらのコメントはスキップされます。設定 → チャネル → TikTok で再接続してください。"
+ }
},
"commentAutomationMissedComments": {
"action": "見逃したコメントを処理",
diff --git a/apps/builder/messages/nl.json b/apps/builder/messages/nl.json
index 4bf994c8d2..c8a17c3831 100644
--- a/apps/builder/messages/nl.json
+++ b/apps/builder/messages/nl.json
@@ -781,7 +781,9 @@
"engagedOnOtherPost": "Al gereageerd op een ander bericht",
"mentionCountNotMatched": "Aantal vermeldingen kwam niet overeen",
"noImageAttachment": "Geen foto bijgevoegd",
- "moderated": "Verborgen of verwijderd door moderatie"
+ "moderated": "Verborgen of verwijderd door moderatie",
+ "postHashtagNotMatched": "Bericht heeft geen overeenkomende hashtag",
+ "postCaptionUnavailable": "Tekst van het bericht kon niet worden gelezen"
},
"replyTo": {
"mentions": "Reacties met genoeg vermeldingen",
@@ -903,6 +905,15 @@
"previous": "Vorige",
"next": "Volgende",
"page": "Pagina {page} van {pageCount}"
+ },
+ "postType": {
+ "hashtags": "Berichten met hashtags"
+ },
+ "postHashtags": {
+ "label": "Hashtags",
+ "description": "Alleen reageren op berichten waarvan de tekst minstens één van deze hashtags bevat. Typ een hashtag en druk op Enter. Een hashtag die later aan een bericht wordt toegevoegd, wordt binnen ongeveer 10 minuten herkend.",
+ "placeholder": "bijv. automation",
+ "required": "Voeg minstens één hashtag toe."
}
},
"fields": {
@@ -6800,7 +6811,8 @@
"delayMustBeZero": "Delay value must be zero for the selected timing option.",
"atLeastOneFieldRequired": "At least one field is required.",
"replyTextRequired": "Voer minstens één antwoordbericht in.",
- "hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword."
+ "hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword.",
+ "hashtagsRequired": "Voeg minstens één hashtag toe."
},
"hideCommentsDescription": "Alleen antwoorden op het hoogste niveau op je berichten kunnen worden verborgen.",
"hideComments": {
@@ -6916,13 +6928,18 @@
"delayMustBeZero": "Delay value must be zero for the selected timing option.",
"hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword.",
"atLeastOneFieldRequired": "At least one field is required.",
- "replyTextRequired": "Voer minstens één antwoordbericht in."
+ "replyTextRequired": "Voer minstens één antwoordbericht in.",
+ "hashtagsRequired": "Voeg minstens één hashtag toe."
},
"privateReply": "Private reply (Comment-to-Message)",
"privateReplyDescription": "Send a direct message to the commenter. TikTok only allows this for comments it flags as high intent, so it will not fire for every matching comment.",
"privateReplyMessage": "Private reply message",
"privateReplyHighIntentTitle": "TikTok decides which comments can be messaged",
- "privateReplyHighIntentNotice": "Comment-to-Message must be enabled on the connected TikTok account, and the account must be a Business Account registered in Vietnam, Indonesia or Thailand. TikTok sends the direct message only for first-level comments it flags as high intent, within 48 hours, once per comment, and not if the commenter already messaged you in the past 24 hours."
+ "privateReplyHighIntentNotice": "Comment-to-Message must be enabled on the connected TikTok account, and the account must be a Business Account registered in Vietnam, Indonesia or Thailand. TikTok sends the direct message only for first-level comments it flags as high intent, within 48 hours, once per comment, and not if the commenter already messaged you in the past 24 hours.",
+ "postHashtags": {
+ "reconnectRequired": "Dit TikTok-account kan nog geen videobeschrijvingen lezen, dus alle reacties worden overgeslagen. Koppel het account opnieuw via Instellingen → Kanalen → TikTok om dit toe te staan.",
+ "someAccountsReconnectRequired": "Sommige van je TikTok-accounts kunnen nog geen videobeschrijvingen lezen, dus hun reacties worden overgeslagen. Koppel ze opnieuw via Instellingen → Kanalen → TikTok."
+ }
},
"commentAutomationMissedComments": {
"action": "Gemiste reacties verwerken",
diff --git a/apps/builder/messages/pt-BR.json b/apps/builder/messages/pt-BR.json
index 01a6e8f259..4be24db157 100644
--- a/apps/builder/messages/pt-BR.json
+++ b/apps/builder/messages/pt-BR.json
@@ -781,7 +781,9 @@
"engagedOnOtherPost": "Já interagiu em outra publicação",
"mentionCountNotMatched": "O número de menções não correspondeu",
"noImageAttachment": "Nenhuma foto anexada",
- "moderated": "Ocultado ou excluído pela moderação"
+ "moderated": "Ocultado ou excluído pela moderação",
+ "postHashtagNotMatched": "O post não tem hashtag correspondente",
+ "postCaptionUnavailable": "Não foi possível ler o texto do post"
},
"replyTo": {
"mentions": "Comentários com menções suficientes",
@@ -903,6 +905,15 @@
"previous": "Anterior",
"next": "Próxima",
"page": "Página {page} de {pageCount}"
+ },
+ "postType": {
+ "hashtags": "Posts com hashtags"
+ },
+ "postHashtags": {
+ "label": "Hashtags",
+ "description": "Responder apenas em posts cujo texto contenha pelo menos uma destas hashtags. Digite uma hashtag e pressione Enter. Uma hashtag adicionada depois a um post é detectada em cerca de 10 minutos.",
+ "placeholder": "ex.: automation",
+ "required": "Adicione pelo menos uma hashtag."
}
},
"condition": {
@@ -6433,7 +6444,8 @@
"delayMustBeZero": "Delay value must be zero for the selected timing option.",
"atLeastOneFieldRequired": "At least one field is required.",
"replyTextRequired": "Insira pelo menos uma mensagem de resposta.",
- "hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword."
+ "hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword.",
+ "hashtagsRequired": "Adicione pelo menos uma hashtag."
},
"hideCommentsDescription": "Somente respostas de primeiro nível às suas publicações podem ser ocultadas.",
"hideComments": {
@@ -6549,13 +6561,18 @@
"delayMustBeZero": "Delay value must be zero for the selected timing option.",
"hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword.",
"atLeastOneFieldRequired": "At least one field is required.",
- "replyTextRequired": "Insira pelo menos uma mensagem de resposta."
+ "replyTextRequired": "Insira pelo menos uma mensagem de resposta.",
+ "hashtagsRequired": "Adicione pelo menos uma hashtag."
},
"privateReply": "Private reply (Comment-to-Message)",
"privateReplyDescription": "Send a direct message to the commenter. TikTok only allows this for comments it flags as high intent, so it will not fire for every matching comment.",
"privateReplyMessage": "Private reply message",
"privateReplyHighIntentTitle": "TikTok decides which comments can be messaged",
- "privateReplyHighIntentNotice": "Comment-to-Message must be enabled on the connected TikTok account, and the account must be a Business Account registered in Vietnam, Indonesia or Thailand. TikTok sends the direct message only for first-level comments it flags as high intent, within 48 hours, once per comment, and not if the commenter already messaged you in the past 24 hours."
+ "privateReplyHighIntentNotice": "Comment-to-Message must be enabled on the connected TikTok account, and the account must be a Business Account registered in Vietnam, Indonesia or Thailand. TikTok sends the direct message only for first-level comments it flags as high intent, within 48 hours, once per comment, and not if the commenter already messaged you in the past 24 hours.",
+ "postHashtags": {
+ "reconnectRequired": "Esta conta do TikTok ainda não consegue ler as descrições dos vídeos, então todos os comentários serão ignorados. Reconecte a conta em Configurações → Canais → TikTok para permitir.",
+ "someAccountsReconnectRequired": "Algumas das suas contas do TikTok ainda não conseguem ler as descrições dos vídeos, então os comentários delas serão ignorados. Reconecte-as em Configurações → Canais → TikTok."
+ }
},
"commentAutomationMissedComments": {
"action": "Processar comentários perdidos",
diff --git a/apps/builder/messages/pt-PT.json b/apps/builder/messages/pt-PT.json
index 7db0e68d29..f1e4a12e71 100644
--- a/apps/builder/messages/pt-PT.json
+++ b/apps/builder/messages/pt-PT.json
@@ -781,7 +781,9 @@
"engagedOnOtherPost": "Já interagiu noutra publicação",
"mentionCountNotMatched": "O número de menções não correspondeu",
"noImageAttachment": "Nenhuma fotografia anexada",
- "moderated": "Ocultado ou eliminado pela moderação"
+ "moderated": "Ocultado ou eliminado pela moderação",
+ "postHashtagNotMatched": "A publicação não tem uma hashtag correspondente",
+ "postCaptionUnavailable": "Não foi possível ler o texto da publicação"
},
"replyTo": {
"mentions": "Comentários com menções suficientes",
@@ -903,6 +905,15 @@
"previous": "Anterior",
"next": "Seguinte",
"page": "Página {page} de {pageCount}"
+ },
+ "postType": {
+ "hashtags": "Publicações com hashtags"
+ },
+ "postHashtags": {
+ "label": "Hashtags",
+ "description": "Responder apenas a publicações cujo texto contenha pelo menos uma destas hashtags. Escreva uma hashtag e prima Enter. Uma hashtag adicionada mais tarde a uma publicação é detetada em cerca de 10 minutos.",
+ "placeholder": "p. ex. automation",
+ "required": "Adicione pelo menos uma hashtag."
}
},
"condition": {
@@ -6796,7 +6807,8 @@
"delayMustBeZero": "Delay value must be zero for the selected timing option.",
"atLeastOneFieldRequired": "At least one field is required.",
"replyTextRequired": "Introduza pelo menos uma mensagem de resposta.",
- "hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword."
+ "hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword.",
+ "hashtagsRequired": "Adicione pelo menos uma hashtag."
},
"hideCommentsDescription": "Apenas as respostas de primeiro nível às suas publicações podem ser ocultadas.",
"hideComments": {
@@ -6912,13 +6924,18 @@
"delayMustBeZero": "Delay value must be zero for the selected timing option.",
"hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword.",
"atLeastOneFieldRequired": "At least one field is required.",
- "replyTextRequired": "Introduza pelo menos uma mensagem de resposta."
+ "replyTextRequired": "Introduza pelo menos uma mensagem de resposta.",
+ "hashtagsRequired": "Adicione pelo menos uma hashtag."
},
"privateReply": "Private reply (Comment-to-Message)",
"privateReplyDescription": "Send a direct message to the commenter. TikTok only allows this for comments it flags as high intent, so it will not fire for every matching comment.",
"privateReplyMessage": "Private reply message",
"privateReplyHighIntentTitle": "TikTok decides which comments can be messaged",
- "privateReplyHighIntentNotice": "Comment-to-Message must be enabled on the connected TikTok account, and the account must be a Business Account registered in Vietnam, Indonesia or Thailand. TikTok sends the direct message only for first-level comments it flags as high intent, within 48 hours, once per comment, and not if the commenter already messaged you in the past 24 hours."
+ "privateReplyHighIntentNotice": "Comment-to-Message must be enabled on the connected TikTok account, and the account must be a Business Account registered in Vietnam, Indonesia or Thailand. TikTok sends the direct message only for first-level comments it flags as high intent, within 48 hours, once per comment, and not if the commenter already messaged you in the past 24 hours.",
+ "postHashtags": {
+ "reconnectRequired": "Esta conta do TikTok ainda não consegue ler as descrições dos vídeos, por isso todos os comentários serão ignorados. Volte a ligar a conta em Definições → Canais → TikTok para o permitir.",
+ "someAccountsReconnectRequired": "Algumas das suas contas do TikTok ainda não conseguem ler as descrições dos vídeos, por isso os comentários delas serão ignorados. Volte a ligá-las em Definições → Canais → TikTok."
+ }
},
"commentAutomationMissedComments": {
"action": "Processar comentários perdidos",
diff --git a/apps/builder/messages/ro.json b/apps/builder/messages/ro.json
index 2082826c7f..c6be7baf0c 100644
--- a/apps/builder/messages/ro.json
+++ b/apps/builder/messages/ro.json
@@ -2178,7 +2178,9 @@
"engagedOnOtherPost": "A interacționat deja la altă postare",
"mentionCountNotMatched": "Numărul de mențiuni nu s-a potrivit",
"noImageAttachment": "Nicio fotografie atașată",
- "moderated": "Ascuns sau șters de moderare"
+ "moderated": "Ascuns sau șters de moderare",
+ "postHashtagNotMatched": "Postarea nu are niciun hashtag potrivit",
+ "postCaptionUnavailable": "Textul postării nu a putut fi citit"
},
"replyTo": {
"mentions": "Comentarii cu suficiente mențiuni",
@@ -2300,6 +2302,15 @@
"previous": "Înapoi",
"next": "Înainte",
"page": "Pagina {page} din {pageCount}"
+ },
+ "postType": {
+ "hashtags": "Postări cu hashtaguri"
+ },
+ "postHashtags": {
+ "label": "Hashtaguri",
+ "description": "Răspunde doar la postările al căror text conține cel puțin unul dintre aceste hashtaguri. Scrie un hashtag și apasă Enter. Un hashtag adăugat ulterior unei postări este detectat în aproximativ 10 minute.",
+ "placeholder": "ex. automation",
+ "required": "Adaugă cel puțin un hashtag."
}
},
"condition": {
@@ -6981,7 +6992,8 @@
"delayMustBeZero": "Delay value must be zero for the selected timing option.",
"atLeastOneFieldRequired": "At least one field is required.",
"replyTextRequired": "Introdu cel puțin un mesaj de răspuns.",
- "hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword."
+ "hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword.",
+ "hashtagsRequired": "Adaugă cel puțin un hashtag."
},
"hideCommentsDescription": "Doar răspunsurile de prim nivel la postările tale pot fi ascunse.",
"hideComments": {
@@ -7097,13 +7109,18 @@
"delayMustBeZero": "Delay value must be zero for the selected timing option.",
"hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword.",
"atLeastOneFieldRequired": "At least one field is required.",
- "replyTextRequired": "Introdu cel puțin un mesaj de răspuns."
+ "replyTextRequired": "Introdu cel puțin un mesaj de răspuns.",
+ "hashtagsRequired": "Adaugă cel puțin un hashtag."
},
"privateReply": "Private reply (Comment-to-Message)",
"privateReplyDescription": "Send a direct message to the commenter. TikTok only allows this for comments it flags as high intent, so it will not fire for every matching comment.",
"privateReplyMessage": "Private reply message",
"privateReplyHighIntentTitle": "TikTok decides which comments can be messaged",
- "privateReplyHighIntentNotice": "Comment-to-Message must be enabled on the connected TikTok account, and the account must be a Business Account registered in Vietnam, Indonesia or Thailand. TikTok sends the direct message only for first-level comments it flags as high intent, within 48 hours, once per comment, and not if the commenter already messaged you in the past 24 hours."
+ "privateReplyHighIntentNotice": "Comment-to-Message must be enabled on the connected TikTok account, and the account must be a Business Account registered in Vietnam, Indonesia or Thailand. TikTok sends the direct message only for first-level comments it flags as high intent, within 48 hours, once per comment, and not if the commenter already messaged you in the past 24 hours.",
+ "postHashtags": {
+ "reconnectRequired": "Acest cont TikTok nu poate încă citi descrierile videoclipurilor, așa că toate comentariile vor fi omise. Reconectează contul din Setări → Canale → TikTok pentru a permite acest lucru.",
+ "someAccountsReconnectRequired": "Unele dintre conturile tale TikTok nu pot încă citi descrierile videoclipurilor, așa că comentariile lor vor fi omise. Reconectează-le din Setări → Canale → TikTok."
+ }
},
"commentAutomationMissedComments": {
"action": "Procesează comentariile ratate",
diff --git a/apps/builder/messages/sv.json b/apps/builder/messages/sv.json
index cef701ebb1..999eb11eeb 100644
--- a/apps/builder/messages/sv.json
+++ b/apps/builder/messages/sv.json
@@ -947,7 +947,9 @@
"engagedOnOtherPost": "Har redan interagerat på ett annat inlägg",
"mentionCountNotMatched": "Antalet omnämnanden stämde inte",
"noImageAttachment": "Ingen bild bifogad",
- "moderated": "Dold eller borttagen av moderering"
+ "moderated": "Dold eller borttagen av moderering",
+ "postHashtagNotMatched": "Inlägget har ingen matchande hashtagg",
+ "postCaptionUnavailable": "Inläggets text kunde inte läsas"
},
"replyTo": {
"mentions": "Kommentarer med tillräckligt många omnämnanden",
@@ -1069,6 +1071,15 @@
"previous": "Föregående",
"next": "Nästa",
"page": "Sida {page} av {pageCount}"
+ },
+ "postType": {
+ "hashtags": "Inlägg med hashtaggar"
+ },
+ "postHashtags": {
+ "label": "Hashtaggar",
+ "description": "Svara bara på inlägg vars text innehåller minst en av dessa hashtaggar. Skriv en hashtagg och tryck på Enter. En hashtagg som läggs till i ett inlägg senare upptäcks inom cirka 10 minuter.",
+ "placeholder": "t.ex. automation",
+ "required": "Lägg till minst en hashtagg."
}
},
"channels": {
@@ -4806,7 +4817,8 @@
"delayMustBeZero": "Delay value must be zero for the selected timing option.",
"atLeastOneFieldRequired": "At least one field is required.",
"replyTextRequired": "Ange minst ett svarsmeddelande.",
- "hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword."
+ "hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword.",
+ "hashtagsRequired": "Lägg till minst en hashtagg."
},
"hideCommentsDescription": "Endast svar på översta nivån till dina inlägg kan döljas.",
"hideComments": {
@@ -4922,13 +4934,18 @@
"delayMustBeZero": "Delay value must be zero for the selected timing option.",
"hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword.",
"atLeastOneFieldRequired": "At least one field is required.",
- "replyTextRequired": "Ange minst ett svarsmeddelande."
+ "replyTextRequired": "Ange minst ett svarsmeddelande.",
+ "hashtagsRequired": "Lägg till minst en hashtagg."
},
"privateReply": "Private reply (Comment-to-Message)",
"privateReplyDescription": "Send a direct message to the commenter. TikTok only allows this for comments it flags as high intent, so it will not fire for every matching comment.",
"privateReplyMessage": "Private reply message",
"privateReplyHighIntentTitle": "TikTok decides which comments can be messaged",
- "privateReplyHighIntentNotice": "Comment-to-Message must be enabled on the connected TikTok account, and the account must be a Business Account registered in Vietnam, Indonesia or Thailand. TikTok sends the direct message only for first-level comments it flags as high intent, within 48 hours, once per comment, and not if the commenter already messaged you in the past 24 hours."
+ "privateReplyHighIntentNotice": "Comment-to-Message must be enabled on the connected TikTok account, and the account must be a Business Account registered in Vietnam, Indonesia or Thailand. TikTok sends the direct message only for first-level comments it flags as high intent, within 48 hours, once per comment, and not if the commenter already messaged you in the past 24 hours.",
+ "postHashtags": {
+ "reconnectRequired": "Det här TikTok-kontot kan ännu inte läsa videobeskrivningar, så alla kommentarer hoppas över. Anslut kontot igen under Inställningar → Kanaler → TikTok för att tillåta det.",
+ "someAccountsReconnectRequired": "Några av dina TikTok-konton kan ännu inte läsa videobeskrivningar, så deras kommentarer hoppas över. Anslut dem igen under Inställningar → Kanaler → TikTok."
+ }
},
"commentAutomationMissedComments": {
"action": "Bearbeta missade kommentarer",
diff --git a/apps/builder/messages/tr.json b/apps/builder/messages/tr.json
index 38f966195f..6e7df3f40d 100644
--- a/apps/builder/messages/tr.json
+++ b/apps/builder/messages/tr.json
@@ -781,7 +781,9 @@
"engagedOnOtherPost": "Başka bir gönderide zaten etkileşime girdi",
"mentionCountNotMatched": "Bahsetme sayısı eşleşmedi",
"noImageAttachment": "Fotoğraf eklenmemiş",
- "moderated": "Moderasyon tarafından gizlendi veya silindi"
+ "moderated": "Moderasyon tarafından gizlendi veya silindi",
+ "postHashtagNotMatched": "Gönderide eşleşen hashtag yok",
+ "postCaptionUnavailable": "Gönderi metni okunamadı"
},
"replyTo": {
"mentions": "Yeterli bahsetme içeren yorumlar",
@@ -903,6 +905,15 @@
"previous": "Önceki",
"next": "Sonraki",
"page": "Sayfa {page} / {pageCount}"
+ },
+ "postType": {
+ "hashtags": "Hashtag içeren gönderiler"
+ },
+ "postHashtags": {
+ "label": "Hashtag'ler",
+ "description": "Yalnızca metninde bu hashtag'lerden en az biri bulunan gönderilere yanıt verin. Bir hashtag yazıp Enter'a basın. Bir gönderiye sonradan eklenen hashtag yaklaşık 10 dakika içinde algılanır.",
+ "placeholder": "örn. automation",
+ "required": "En az bir hashtag ekleyin."
}
},
"condition": {
@@ -6800,7 +6811,8 @@
"delayMustBeZero": "Delay value must be zero for the selected timing option.",
"atLeastOneFieldRequired": "At least one field is required.",
"replyTextRequired": "En az bir yanıt mesajı girin.",
- "hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword."
+ "hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword.",
+ "hashtagsRequired": "En az bir hashtag ekleyin."
},
"hideCommentsDescription": "Yalnızca gönderilerinize verilen üst düzey yanıtlar gizlenebilir.",
"hideComments": {
@@ -6916,13 +6928,18 @@
"delayMustBeZero": "Delay value must be zero for the selected timing option.",
"hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword.",
"atLeastOneFieldRequired": "At least one field is required.",
- "replyTextRequired": "En az bir yanıt mesajı girin."
+ "replyTextRequired": "En az bir yanıt mesajı girin.",
+ "hashtagsRequired": "En az bir hashtag ekleyin."
},
"privateReply": "Private reply (Comment-to-Message)",
"privateReplyDescription": "Send a direct message to the commenter. TikTok only allows this for comments it flags as high intent, so it will not fire for every matching comment.",
"privateReplyMessage": "Private reply message",
"privateReplyHighIntentTitle": "TikTok decides which comments can be messaged",
- "privateReplyHighIntentNotice": "Comment-to-Message must be enabled on the connected TikTok account, and the account must be a Business Account registered in Vietnam, Indonesia or Thailand. TikTok sends the direct message only for first-level comments it flags as high intent, within 48 hours, once per comment, and not if the commenter already messaged you in the past 24 hours."
+ "privateReplyHighIntentNotice": "Comment-to-Message must be enabled on the connected TikTok account, and the account must be a Business Account registered in Vietnam, Indonesia or Thailand. TikTok sends the direct message only for first-level comments it flags as high intent, within 48 hours, once per comment, and not if the commenter already messaged you in the past 24 hours.",
+ "postHashtags": {
+ "reconnectRequired": "Bu TikTok hesabı henüz video açıklamalarını okuyamıyor, bu yüzden tüm yorumlar atlanacak. İzin vermek için hesabı Ayarlar → Kanallar → TikTok bölümünden yeniden bağlayın.",
+ "someAccountsReconnectRequired": "Bazı TikTok hesaplarınız henüz video açıklamalarını okuyamıyor, bu yüzden yorumları atlanacak. Onları Ayarlar → Kanallar → TikTok bölümünden yeniden bağlayın."
+ }
},
"commentAutomationMissedComments": {
"action": "Kaçırılan yorumları işle",
diff --git a/apps/builder/messages/vi.json b/apps/builder/messages/vi.json
index 3ba05ecab8..8770aefa35 100644
--- a/apps/builder/messages/vi.json
+++ b/apps/builder/messages/vi.json
@@ -823,7 +823,9 @@
"engagedOnOtherPost": "Đã tương tác ở bài viết khác",
"mentionCountNotMatched": "Số lượt nhắc tên không khớp",
"noImageAttachment": "Không có ảnh đính kèm",
- "moderated": "Đã bị ẩn hoặc xoá khi kiểm duyệt"
+ "moderated": "Đã bị ẩn hoặc xoá khi kiểm duyệt",
+ "postHashtagNotMatched": "Bài viết không có hashtag phù hợp",
+ "postCaptionUnavailable": "Không đọc được nội dung bài viết"
},
"replyTo": {
"mentions": "Bình luận có đủ số người được nhắc tên",
@@ -945,6 +947,15 @@
"previous": "Trước",
"next": "Sau",
"page": "Trang {page}/{pageCount}"
+ },
+ "postType": {
+ "hashtags": "Bài viết có hashtag"
+ },
+ "postHashtags": {
+ "label": "Hashtag",
+ "description": "Chỉ trả lời ở bài viết có ít nhất một hashtag trong danh sách này. Gõ hashtag rồi nhấn Enter. Nếu bạn sửa bài để thêm hashtag sau, hệ thống sẽ nhận ra trong khoảng 10 phút.",
+ "placeholder": "ví dụ: automation",
+ "required": "Hãy thêm ít nhất một hashtag."
}
},
"condition": {
@@ -6890,7 +6901,8 @@
"delayMustBeZero": "Giá trị độ trễ phải bằng 0 với tùy chọn thời gian đã chọn.",
"atLeastOneFieldRequired": "Cần ít nhất một trường để cập nhật.",
"replyTextRequired": "Nhập ít nhất một tin nhắn trả lời.",
- "hideKeywordsRequired": "Nhập ít nhất một từ khóa để ẩn bình luận theo từ khóa."
+ "hideKeywordsRequired": "Nhập ít nhất một từ khóa để ẩn bình luận theo từ khóa.",
+ "hashtagsRequired": "Hãy thêm ít nhất một hashtag."
},
"hideCommentsDescription": "Chỉ có thể ẩn các trả lời cấp cao nhất trên bài viết của bạn.",
"hideComments": {
@@ -7006,13 +7018,18 @@
"delayMustBeZero": "Giá trị độ trễ phải bằng 0 với tùy chọn thời điểm đã chọn.",
"hideKeywordsRequired": "Nhập ít nhất một từ khóa để ẩn bình luận theo từ khóa.",
"atLeastOneFieldRequired": "Cần ít nhất một trường.",
- "replyTextRequired": "Nhập ít nhất một tin nhắn trả lời."
+ "replyTextRequired": "Nhập ít nhất một tin nhắn trả lời.",
+ "hashtagsRequired": "Hãy thêm ít nhất một hashtag."
},
"privateReply": "Trả lời riêng (Comment-to-Message)",
"privateReplyDescription": "Gửi tin nhắn riêng cho người bình luận. TikTok chỉ cho phép với bình luận được TikTok đánh dấu là có ý định mua cao, nên sẽ không chạy với mọi bình luận khớp điều kiện.",
"privateReplyMessage": "Nội dung tin nhắn riêng",
"privateReplyHighIntentTitle": "TikTok quyết định bình luận nào được nhắn tin",
- "privateReplyHighIntentNotice": "Tài khoản TikTok đã kết nối phải bật Comment-to-Message, và phải là Business Account đăng ký tại Việt Nam, Indonesia hoặc Thái Lan. TikTok chỉ gửi tin nhắn riêng cho bình luận cấp 1 mà TikTok đánh dấu là có ý định mua cao, trong vòng 48 giờ, mỗi bình luận một lần, và không gửi nếu người bình luận đã nhắn tin cho bạn trong 24 giờ qua."
+ "privateReplyHighIntentNotice": "Tài khoản TikTok đã kết nối phải bật Comment-to-Message, và phải là Business Account đăng ký tại Việt Nam, Indonesia hoặc Thái Lan. TikTok chỉ gửi tin nhắn riêng cho bình luận cấp 1 mà TikTok đánh dấu là có ý định mua cao, trong vòng 48 giờ, mỗi bình luận một lần, và không gửi nếu người bình luận đã nhắn tin cho bạn trong 24 giờ qua.",
+ "postHashtags": {
+ "reconnectRequired": "Tài khoản TikTok này chưa có quyền đọc nội dung video, nên mọi bình luận sẽ bị bỏ qua. Hãy kết nối lại tài khoản trong Cài đặt → Kênh → TikTok để cấp quyền.",
+ "someAccountsReconnectRequired": "Một số tài khoản TikTok chưa có quyền đọc nội dung video, nên bình luận của các tài khoản đó sẽ bị bỏ qua. Hãy kết nối lại trong Cài đặt → Kênh → TikTok."
+ }
},
"commentAutomationMissedComments": {
"action": "Xử lý bình luận bị bỏ sót",
diff --git a/apps/builder/messages/zh-CN.json b/apps/builder/messages/zh-CN.json
index b68edb86f6..c1ba5eb3cb 100644
--- a/apps/builder/messages/zh-CN.json
+++ b/apps/builder/messages/zh-CN.json
@@ -1135,7 +1135,9 @@
"engagedOnOtherPost": "已在其他帖子互动过",
"mentionCountNotMatched": "提及人数不匹配",
"noImageAttachment": "未附带图片",
- "moderated": "已被审核隐藏或删除"
+ "moderated": "已被审核隐藏或删除",
+ "postHashtagNotMatched": "帖子没有匹配的话题标签",
+ "postCaptionUnavailable": "无法读取帖子正文"
},
"replyTo": {
"mentions": "提及人数足够的评论",
@@ -1257,6 +1259,15 @@
"previous": "上一页",
"next": "下一页",
"page": "第 {page} 页,共 {pageCount} 页"
+ },
+ "postType": {
+ "hashtags": "带话题标签的帖子"
+ },
+ "postHashtags": {
+ "label": "话题标签",
+ "description": "仅回复正文包含以下至少一个话题标签的帖子。输入话题标签后按 Enter。之后添加到帖子的话题标签会在约 10 分钟内生效。",
+ "placeholder": "例如:automation",
+ "required": "请至少添加一个话题标签。"
}
},
"channels": {
@@ -4806,7 +4817,8 @@
"delayMustBeZero": "所选的时机选项不支持延迟时间,请设为零。",
"atLeastOneFieldRequired": "请至少填写一个字段。",
"replyTextRequired": "请至少输入一条回复消息。",
- "hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword."
+ "hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword.",
+ "hashtagsRequired": "请至少添加一个话题标签。"
},
"hideCommentsDescription": "只能隐藏您帖子下的顶级回复。",
"hideComments": {
@@ -4922,13 +4934,18 @@
"delayMustBeZero": "Delay value must be zero for the selected timing option.",
"hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword.",
"atLeastOneFieldRequired": "At least one field is required.",
- "replyTextRequired": "请至少输入一条回复消息。"
+ "replyTextRequired": "请至少输入一条回复消息。",
+ "hashtagsRequired": "请至少添加一个话题标签。"
},
"privateReply": "Private reply (Comment-to-Message)",
"privateReplyDescription": "Send a direct message to the commenter. TikTok only allows this for comments it flags as high intent, so it will not fire for every matching comment.",
"privateReplyMessage": "Private reply message",
"privateReplyHighIntentTitle": "TikTok decides which comments can be messaged",
- "privateReplyHighIntentNotice": "Comment-to-Message must be enabled on the connected TikTok account, and the account must be a Business Account registered in Vietnam, Indonesia or Thailand. TikTok sends the direct message only for first-level comments it flags as high intent, within 48 hours, once per comment, and not if the commenter already messaged you in the past 24 hours."
+ "privateReplyHighIntentNotice": "Comment-to-Message must be enabled on the connected TikTok account, and the account must be a Business Account registered in Vietnam, Indonesia or Thailand. TikTok sends the direct message only for first-level comments it flags as high intent, within 48 hours, once per comment, and not if the commenter already messaged you in the past 24 hours.",
+ "postHashtags": {
+ "reconnectRequired": "此 TikTok 账号暂时无法读取视频描述,因此所有评论都会被跳过。请在 设置 → 渠道 → TikTok 中重新连接账号以授权。",
+ "someAccountsReconnectRequired": "部分 TikTok 账号暂时无法读取视频描述,因此它们的评论会被跳过。请在 设置 → 渠道 → TikTok 中重新连接。"
+ }
},
"commentAutomationMissedComments": {
"action": "处理遗漏的评论",
diff --git a/apps/builder/messages/zh-TW.json b/apps/builder/messages/zh-TW.json
index 46911182a7..4c8b6dc997 100644
--- a/apps/builder/messages/zh-TW.json
+++ b/apps/builder/messages/zh-TW.json
@@ -2735,7 +2735,9 @@
"engagedOnOtherPost": "已在其他貼文互動過",
"mentionCountNotMatched": "提及人數不符",
"noImageAttachment": "未附加圖片",
- "moderated": "已被審核隱藏或刪除"
+ "moderated": "已被審核隱藏或刪除",
+ "postHashtagNotMatched": "貼文沒有相符的主題標籤",
+ "postCaptionUnavailable": "無法讀取貼文內文"
},
"replyTo": {
"mentions": "提及人數足夠的留言",
@@ -2857,6 +2859,15 @@
"previous": "上一頁",
"next": "下一頁",
"page": "第 {page} 頁,共 {pageCount} 頁"
+ },
+ "postType": {
+ "hashtags": "帶有主題標籤的貼文"
+ },
+ "postHashtags": {
+ "label": "主題標籤",
+ "description": "僅回覆內文包含下列至少一個主題標籤的貼文。輸入主題標籤後按 Enter。之後加入貼文的主題標籤會在約 10 分鐘內生效。",
+ "placeholder": "例如:automation",
+ "required": "請至少新增一個主題標籤。"
}
},
"condition": {
@@ -6846,7 +6857,8 @@
"delayMustBeZero": "所選的時機選項不支援延遲時間,請設為零。",
"atLeastOneFieldRequired": "請至少填寫一個欄位。",
"replyTextRequired": "請至少輸入一則回覆訊息。",
- "hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword."
+ "hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword.",
+ "hashtagsRequired": "請至少新增一個主題標籤。"
},
"hideCommentsDescription": "只能隱藏您貼文下的頂層回覆。",
"hideComments": {
@@ -6962,13 +6974,18 @@
"delayMustBeZero": "Delay value must be zero for the selected timing option.",
"hideKeywordsRequired": "Enter at least one keyword to hide comments by keyword.",
"atLeastOneFieldRequired": "At least one field is required.",
- "replyTextRequired": "請至少輸入一則回覆訊息。"
+ "replyTextRequired": "請至少輸入一則回覆訊息。",
+ "hashtagsRequired": "請至少新增一個主題標籤。"
},
"privateReply": "Private reply (Comment-to-Message)",
"privateReplyDescription": "Send a direct message to the commenter. TikTok only allows this for comments it flags as high intent, so it will not fire for every matching comment.",
"privateReplyMessage": "Private reply message",
"privateReplyHighIntentTitle": "TikTok decides which comments can be messaged",
- "privateReplyHighIntentNotice": "Comment-to-Message must be enabled on the connected TikTok account, and the account must be a Business Account registered in Vietnam, Indonesia or Thailand. TikTok sends the direct message only for first-level comments it flags as high intent, within 48 hours, once per comment, and not if the commenter already messaged you in the past 24 hours."
+ "privateReplyHighIntentNotice": "Comment-to-Message must be enabled on the connected TikTok account, and the account must be a Business Account registered in Vietnam, Indonesia or Thailand. TikTok sends the direct message only for first-level comments it flags as high intent, within 48 hours, once per comment, and not if the commenter already messaged you in the past 24 hours.",
+ "postHashtags": {
+ "reconnectRequired": "此 TikTok 帳號目前無法讀取影片說明,因此所有留言都會被略過。請在 設定 → 頻道 → TikTok 中重新連結帳號以授權。",
+ "someAccountsReconnectRequired": "部分 TikTok 帳號目前無法讀取影片說明,因此它們的留言會被略過。請在 設定 → 頻道 → TikTok 中重新連結。"
+ }
},
"commentAutomationMissedComments": {
"action": "處理遺漏的留言",
diff --git a/apps/builder/src/app/space/[workspaceId]/tiktok-comments/[id]/page.tsx b/apps/builder/src/app/space/[workspaceId]/tiktok-comments/[id]/page.tsx
index a68999c5e6..cf0cd2330c 100644
--- a/apps/builder/src/app/space/[workspaceId]/tiktok-comments/[id]/page.tsx
+++ b/apps/builder/src/app/space/[workspaceId]/tiktok-comments/[id]/page.tsx
@@ -1,7 +1,10 @@
import { notFound } from "next/navigation"
import { LockedEditorGuard } from "@/features/templates/components/locked-editor-guard"
import { EditTiktokCommentForm } from "@/features/tiktok-comments/components/edit-tiktok-comment-form"
-import { getTiktokComment } from "@/features/tiktok-comments/queries"
+import {
+ getTiktokComment,
+ listTiktokInboxIdsWithoutCaptionAccess,
+} from "@/features/tiktok-comments/queries"
import { withWorkspaceIdAndIdSchema } from "@/features/workspaces/schema/resource"
export default async function EditTiktokCommentPage(props: {
@@ -18,6 +21,8 @@ export default async function EditTiktokCommentPage(props: {
if (!record) {
return notFound()
}
+ const captionUnavailableInboxIds =
+ await listTiktokInboxIdsWithoutCaptionAccess(data.workspaceId)
return (
diff --git a/apps/builder/src/app/space/[workspaceId]/tiktok-comments/create/page.tsx b/apps/builder/src/app/space/[workspaceId]/tiktok-comments/create/page.tsx
index 9087b3d49f..38a2e4b644 100644
--- a/apps/builder/src/app/space/[workspaceId]/tiktok-comments/create/page.tsx
+++ b/apps/builder/src/app/space/[workspaceId]/tiktok-comments/create/page.tsx
@@ -1,5 +1,6 @@
import { notFound } from "next/navigation"
import { CreateTiktokCommentForm } from "@/features/tiktok-comments/components/create-tiktok-comment-form"
+import { listTiktokInboxIdsWithoutCaptionAccess } from "@/features/tiktok-comments/queries"
import { withWorkspaceIdSchema } from "@/features/workspaces/schema/resource"
export default async function CreateTiktokCommentPage(props: {
@@ -10,5 +11,13 @@ export default async function CreateTiktokCommentPage(props: {
return notFound()
}
- return
+ const captionUnavailableInboxIds =
+ await listTiktokInboxIdsWithoutCaptionAccess(data.workspaceId)
+
+ return (
+
+ )
}
diff --git a/apps/builder/src/features/fb-comments/components/create-fb-comment-form.tsx b/apps/builder/src/features/fb-comments/components/create-fb-comment-form.tsx
index 1eb72eb183..8d5add1125 100644
--- a/apps/builder/src/features/fb-comments/components/create-fb-comment-form.tsx
+++ b/apps/builder/src/features/fb-comments/components/create-fb-comment-form.tsx
@@ -9,6 +9,7 @@ import type { UseFormReturn } from "react-hook-form"
import { toast } from "sonner"
import { AI_MODERATION_DEFAULTS } from "@/features/shared/comment-automation/lib/ai-moderation-defaults"
import { initialCommentPost } from "@/features/shared/comment-automation/lib/live-post-type"
+import { refinePostHashtags } from "@/features/shared/comment-automation/lib/post-hashtags-validation"
import { createFbCommentAction } from "../actions/create-fb-comment.action"
import {
type CreateFbCommentRequest,
@@ -63,7 +64,11 @@ export function CreateFbCommentForm({
const { form, handleSubmitWithAction } = useHookFormAction(
createFbCommentAction.bind(null, workspaceId),
- zodResolver(createFbCommentRequest),
+ zodResolver(
+ createFbCommentRequest.superRefine(
+ refinePostHashtags(t("commentAutomation.postHashtags.required")),
+ ),
+ ),
{
actionProps: {
onSuccess: () => {
diff --git a/apps/builder/src/features/fb-comments/components/edit-fb-comment-form.tsx b/apps/builder/src/features/fb-comments/components/edit-fb-comment-form.tsx
index 89e064e31d..3f85310c4a 100644
--- a/apps/builder/src/features/fb-comments/components/edit-fb-comment-form.tsx
+++ b/apps/builder/src/features/fb-comments/components/edit-fb-comment-form.tsx
@@ -10,6 +10,7 @@ import { useAction } from "next-safe-action/hooks"
import { type Resolver, type UseFormReturn, useForm } from "react-hook-form"
import { toast } from "sonner"
import { withAIModerationDefaults } from "@/features/shared/comment-automation/lib/ai-moderation-defaults"
+import { refinePostHashtags } from "@/features/shared/comment-automation/lib/post-hashtags-validation"
import { updateFbCommentAction } from "../actions/update-fb-comment.action"
import {
type CreateFbCommentRequest,
@@ -30,7 +31,9 @@ export function EditFbCommentForm({
const form = useForm({
resolver: zodResolver(
- createFbCommentRequest,
+ createFbCommentRequest.superRefine(
+ refinePostHashtags(t("commentAutomation.postHashtags.required")),
+ ),
) as Resolver,
mode: "onChange",
defaultValues: {
diff --git a/apps/builder/src/features/fb-comments/components/fb-comment-form.tsx b/apps/builder/src/features/fb-comments/components/fb-comment-form.tsx
index b9e5d56f43..fce7ffb6e6 100644
--- a/apps/builder/src/features/fb-comments/components/fb-comment-form.tsx
+++ b/apps/builder/src/features/fb-comments/components/fb-comment-form.tsx
@@ -35,8 +35,10 @@ import {
useAccountChoiceMissing,
} from "@/features/shared/comment-automation/automation-account-field"
import { ExcludeKeywordsField } from "@/features/shared/comment-automation/exclude-keywords-field"
+import { PostHashtagsField } from "@/features/shared/comment-automation/post-hashtags-field"
import { ReplyTextsField } from "@/features/shared/comment-automation/reply-texts-field"
import { ReplyToField } from "@/features/shared/comment-automation/reply-to-field"
+import { useClearPostValueOnHashtagsSwitch } from "@/features/shared/comment-automation/use-clear-post-value-on-hashtags-switch"
import { LockedContent } from "@/features/templates/components/locked-editor"
import { useWorkspaceId } from "@/hooks/routing"
import { useFbCommentPostsStore } from "../provider/fb-comment-posts-store-context"
@@ -121,8 +123,13 @@ export function FbCommentForm({
label: t("facebookCommentAutomation.postType.specificPosts"),
value: "postIds",
},
+ { label: t("commentAutomation.postType.hashtags"), value: "hashtags" },
]
+ useClearPostValueOnHashtagsSwitch(postType, () =>
+ form.setValue("post.value", [], { shouldDirty: true }),
+ )
+
const replyAfterTypeOptions = [
{
label: t("facebookCommentAutomation.replyAfterType.immediately"),
@@ -254,6 +261,8 @@ export function FbCommentForm({
>
)}
+ {postType === "hashtags" && }
+
{
diff --git a/apps/builder/src/features/ig-comments/components/edit-ig-comment-form.tsx b/apps/builder/src/features/ig-comments/components/edit-ig-comment-form.tsx
index 41a3b04cd1..55b38f477e 100644
--- a/apps/builder/src/features/ig-comments/components/edit-ig-comment-form.tsx
+++ b/apps/builder/src/features/ig-comments/components/edit-ig-comment-form.tsx
@@ -10,6 +10,7 @@ import { useAction } from "next-safe-action/hooks"
import { type Resolver, type UseFormReturn, useForm } from "react-hook-form"
import { toast } from "sonner"
import { withAIModerationDefaults } from "@/features/shared/comment-automation/lib/ai-moderation-defaults"
+import { refinePostHashtags } from "@/features/shared/comment-automation/lib/post-hashtags-validation"
import { updateIgCommentAction } from "../actions/update-ig-comment.action"
import {
type CreateIgCommentRequest,
@@ -32,7 +33,9 @@ export function EditIgCommentForm({
const form = useForm({
resolver: zodResolver(
- createIgCommentRequest,
+ createIgCommentRequest.superRefine(
+ refinePostHashtags(t("commentAutomation.postHashtags.required")),
+ ),
) as Resolver,
mode: "onChange",
defaultValues: {
diff --git a/apps/builder/src/features/ig-comments/components/ig-comment-form.tsx b/apps/builder/src/features/ig-comments/components/ig-comment-form.tsx
index 8437e18a22..a96ec09e83 100644
--- a/apps/builder/src/features/ig-comments/components/ig-comment-form.tsx
+++ b/apps/builder/src/features/ig-comments/components/ig-comment-form.tsx
@@ -38,8 +38,10 @@ import {
useAccountChoiceMissing,
} from "@/features/shared/comment-automation/automation-account-field"
import { ExcludeKeywordsField } from "@/features/shared/comment-automation/exclude-keywords-field"
+import { PostHashtagsField } from "@/features/shared/comment-automation/post-hashtags-field"
import { ReplyTextsField } from "@/features/shared/comment-automation/reply-texts-field"
import { ReplyToField } from "@/features/shared/comment-automation/reply-to-field"
+import { useClearPostValueOnHashtagsSwitch } from "@/features/shared/comment-automation/use-clear-post-value-on-hashtags-switch"
import { LockedContent } from "@/features/templates/components/locked-editor"
import { useWorkspaceId } from "@/hooks/routing"
import { useIgCommentPostsStore } from "../provider/ig-comment-posts-store-context"
@@ -130,8 +132,13 @@ export function IgCommentForm({
label: t("instagramCommentAutomation.postType.specificPosts"),
value: "postIds",
},
+ { label: t("commentAutomation.postType.hashtags"), value: "hashtags" },
]
+ useClearPostValueOnHashtagsSwitch(postType, () =>
+ form.setValue("post.value", [], { shouldDirty: true }),
+ )
+
const replyAfterTypeOptions = [
{
label: t("instagramCommentAutomation.replyAfterType.immediately"),
@@ -271,6 +278,8 @@ export function IgCommentForm({
>
)}
+ {postType === "hashtags" && }
+
{
+ if (data.post?.type === "hashtags" && data.post.value.length === 0) {
+ ctx.addIssue({ code: "custom", path: ["post", "value"], message })
+ }
+ }
+}
diff --git a/apps/builder/src/features/shared/comment-automation/post-hashtags-field.tsx b/apps/builder/src/features/shared/comment-automation/post-hashtags-field.tsx
new file mode 100644
index 0000000000..351bd687fd
--- /dev/null
+++ b/apps/builder/src/features/shared/comment-automation/post-hashtags-field.tsx
@@ -0,0 +1,56 @@
+"use client"
+
+import {
+ COMMENT_POST_HASHTAG_MAX_LENGTH,
+ COMMENT_POST_HASHTAGS_MAX,
+ isValidCommentPostHashtag,
+ normalizeCommentPostHashtag,
+} from "@chatbotx.io/database/partials"
+import { Alert, AlertDescription } from "@chatbotx.io/ui/components/ui/alert"
+import { TagsInputField } from "@chatbotx.io/ui/components/ui/muhammada86/tags-input-field"
+import { TriangleAlert } from "lucide-react"
+import { useTranslations } from "next-intl"
+
+/**
+ * Stores a typed hashtag in the canonical form the worker compares against
+ * (`#VIP` → `vip`), and drops one a caption could never carry (a space, `-`,
+ * `.`) instead of saving a tag that silently never matches.
+ */
+function toStoredHashtag(raw: string): string {
+ const tag = normalizeCommentPostHashtag(raw)
+ return isValidCommentPostHashtag(tag) ? tag : ""
+}
+
+type Props = {
+ /** Shown above the field, e.g. a TikTok connection that cannot read captions. */
+ warning?: string | null
+}
+
+/**
+ * The hashtag list of a `hashtags` post target: the automation answers a
+ * comment only when the post's caption carries at least one of these.
+ */
+export function PostHashtagsField({ warning }: Props) {
+ const t = useTranslations()
+
+ return (
+
+ {warning && (
+
+
+ {warning}
+
+ )}
+
+
+ )
+}
diff --git a/apps/builder/src/features/shared/comment-automation/use-clear-post-value-on-hashtags-switch.ts b/apps/builder/src/features/shared/comment-automation/use-clear-post-value-on-hashtags-switch.ts
new file mode 100644
index 0000000000..91dd658971
--- /dev/null
+++ b/apps/builder/src/features/shared/comment-automation/use-clear-post-value-on-hashtags-switch.ts
@@ -0,0 +1,27 @@
+"use client"
+
+import { useEffect, useRef } from "react"
+
+/**
+ * `post.value` holds post ids for a `postIds` target and hashtags for a
+ * `hashtags` one. Switching between the two must empty it, or the chosen post
+ * ids would be saved as hashtags (or the reverse). Only fires on an actual
+ * switch, never on the first render, so an edit form keeps its stored list.
+ */
+export function useClearPostValueOnHashtagsSwitch(
+ postType: string,
+ clearPostValue: () => void,
+) {
+ const previousType = useRef(postType)
+ useEffect(() => {
+ if (previousType.current === postType) {
+ return
+ }
+ const crossesHashtags =
+ previousType.current === "hashtags" || postType === "hashtags"
+ previousType.current = postType
+ if (crossesHashtags) {
+ clearPostValue()
+ }
+ }, [postType, clearPostValue])
+}
diff --git a/apps/builder/src/features/threads-comments/components/threads-comment-form.tsx b/apps/builder/src/features/threads-comments/components/threads-comment-form.tsx
index d3dbd4c83b..089e8cdac9 100644
--- a/apps/builder/src/features/threads-comments/components/threads-comment-form.tsx
+++ b/apps/builder/src/features/threads-comments/components/threads-comment-form.tsx
@@ -35,8 +35,10 @@ import {
useAccountChoiceMissing,
} from "@/features/shared/comment-automation/automation-account-field"
import { ExcludeKeywordsField } from "@/features/shared/comment-automation/exclude-keywords-field"
+import { PostHashtagsField } from "@/features/shared/comment-automation/post-hashtags-field"
import { ReplyTextsField } from "@/features/shared/comment-automation/reply-texts-field"
import { ReplyToField } from "@/features/shared/comment-automation/reply-to-field"
+import { useClearPostValueOnHashtagsSwitch } from "@/features/shared/comment-automation/use-clear-post-value-on-hashtags-switch"
import { LockedContent } from "@/features/templates/components/locked-editor"
import { useWorkspaceId } from "@/hooks/routing"
import { useThreadsPosts } from "../hooks/use-threads-posts"
@@ -98,6 +100,10 @@ export function ThreadsCommentForm({
}
}, [isAIAgentsError, t])
+ useClearPostValueOnHashtagsSwitch(postType, () =>
+ form.setValue("post.value", [], { shouldDirty: true }),
+ )
+
useEffect(() => {
if (postType === "all") {
form.setValue("post.value", [], {
@@ -193,6 +199,10 @@ export function ThreadsCommentForm({
label: t("threadsCommentAutomation.postType.specificPosts"),
value: "postIds",
},
+ {
+ label: t("commentAutomation.postType.hashtags"),
+ value: "hashtags",
+ },
]}
orientation="horizontal"
required
@@ -233,6 +243,8 @@ export function ThreadsCommentForm({
/>
) : null}
+ {postType === "hashtags" && }
+
threadsCommentResource.parse({
...record,
- post: {
- type: record.post.type === "postIds" ? "postIds" : "all",
- value: record.post.type === "postIds" ? record.post.value : [],
- },
+ post: toChannelPostTarget(record.post),
privateReply: { type: "none", value: null },
publicReply:
record.publicReply.type === "none"
diff --git a/apps/builder/src/features/threads-comments/schema/action.ts b/apps/builder/src/features/threads-comments/schema/action.ts
index eddcf912ac..6d292855e3 100644
--- a/apps/builder/src/features/threads-comments/schema/action.ts
+++ b/apps/builder/src/features/threads-comments/schema/action.ts
@@ -29,6 +29,7 @@ const MAX_POST_ID_LENGTH = 120
const threadsCommentValidationKeyNames = [
"postIdsMustBeEmptyForAll",
"postIdsRequired",
+ "hashtagsRequired",
"keywordsMustBeEmptyForAll",
"keywordsRequired",
"delayMustBePositive",
@@ -110,7 +111,7 @@ export function createThreadsCommentRequestSchema(
const threadsPostSchema = z
.object({
- type: z.enum(["all", "postIds"]),
+ type: z.enum(["all", "postIds", "hashtags"]),
value: trimmedArray(MAX_POST_IDS, MAX_POST_ID_LENGTH),
})
.superRefine((value, ctx) => {
@@ -128,6 +129,13 @@ export function createThreadsCommentRequestSchema(
message: validationMessages.postIdsRequired,
})
}
+ if (value.type === "hashtags" && value.value.length === 0) {
+ ctx.addIssue({
+ code: "custom",
+ path: ["value"],
+ message: validationMessages.hashtagsRequired,
+ })
+ }
})
// The shared schema owns the include types and the `mentionCount` rule, so
@@ -256,7 +264,7 @@ export function createThreadsCommentRequestSchema(
.describe("Automation name."),
inboxId: automationInboxIdSchema,
post: threadsPostSchema.describe(
- "Which comments to answer: `all` posts or specific `postIds` (get them from `threadsComments.listPosts`).",
+ "Which comments to answer: `all` posts, specific `postIds` (get them from `threadsComments.listPosts`), or `hashtags` — any post whose text carries one of the hashtags in `value` (without `#`).",
),
publicReply: threadsReplySchema.describe(
"Public reply posted under the comment: `text`, a `flow`, an `AIAgent`, or `none`.",
diff --git a/apps/builder/src/features/threads-comments/schema/resource.ts b/apps/builder/src/features/threads-comments/schema/resource.ts
index 6ead468825..f1c8cb9c7a 100644
--- a/apps/builder/src/features/threads-comments/schema/resource.ts
+++ b/apps/builder/src/features/threads-comments/schema/resource.ts
@@ -40,7 +40,7 @@ export const threadsCommentResource = createSelectSchema(
workspaceId: z.string(),
inboxId: automationInboxIdResourceSchema,
post: z.object({
- type: z.enum(["all", "postIds"]),
+ type: z.enum(["all", "postIds", "hashtags"]),
value: z.array(z.string()),
}),
privateReply: z.object({
diff --git a/apps/builder/src/features/tiktok-comments/components/create-tiktok-comment-form.tsx b/apps/builder/src/features/tiktok-comments/components/create-tiktok-comment-form.tsx
index 63f3555d49..4283bcfb2f 100644
--- a/apps/builder/src/features/tiktok-comments/components/create-tiktok-comment-form.tsx
+++ b/apps/builder/src/features/tiktok-comments/components/create-tiktok-comment-form.tsx
@@ -47,8 +47,11 @@ const defaultValues = {
export function CreateTiktokCommentForm({
workspaceId,
+ captionUnavailableInboxIds,
}: {
workspaceId: string
+ /** TikTok accounts that cannot read captions (see the hashtags target). */
+ captionUnavailableInboxIds: string[]
}) {
const t = useTranslations()
const validationMessages = resolveTiktokCommentValidationMessages(t)
@@ -80,6 +83,7 @@ export function CreateTiktokCommentForm({
return (