feat(ui): translation-forward post text + Settings card (#143 step 5)
PostCard + modal ProvenancePanel show the English title/description by default when a translation exists, with a per-card "show original (<lang>)" toggle — translated bodies render as plain text, originals keep their sanitized HTML. New TranslationCard in Settings → Ingestion & filters: enable switch, Interpreter base URL (generic placeholder, no default host), target language, a reachability indicator + untranslated-posts count + "Translate now". Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CDgx8bQS5YrGRK76v8HUnM
This commit is contained in:
@@ -42,13 +42,23 @@
|
||||
· {{ e.post.attachment_count }} files
|
||||
</span>
|
||||
</div>
|
||||
<div v-if="hasTranslation(e)" class="fc-prov__actions">
|
||||
<a
|
||||
href="#" @click.prevent="toggleOrig(e.provenance_id)"
|
||||
>{{ showOrig[e.provenance_id] ? 'Show translation' : `Show original${langLabel(e)}` }}</a>
|
||||
</div>
|
||||
<div v-if="e.post.description_html" class="fc-prov__actions">
|
||||
<a
|
||||
href="#" @click.prevent="toggleDesc(e.provenance_id)"
|
||||
>{{ expanded[e.provenance_id] ? 'Hide description ▴' : 'Show description ▾' }}</a>
|
||||
</div>
|
||||
<!-- Translated body = plain text; original = sanitized HTML (#143). -->
|
||||
<p
|
||||
v-if="showTranslated(e) && expanded[e.provenance_id] && e.post.description_translated"
|
||||
class="fc-prov__desc"
|
||||
>{{ e.post.description_translated }}</p>
|
||||
<div
|
||||
v-if="e.post.description_html && expanded[e.provenance_id]"
|
||||
v-else-if="e.post.description_html && expanded[e.provenance_id]"
|
||||
class="fc-prov__desc" v-html="e.post.description_html"
|
||||
/>
|
||||
</article>
|
||||
@@ -117,8 +127,12 @@ const effectiveImage = computed(() => props.image ?? modal.current)
|
||||
// 2026-05-28. Reset when the viewed image changes.
|
||||
const expanded = reactive({})
|
||||
function toggleDesc(id) { expanded[id] = !expanded[id] }
|
||||
// Per-entry "show the original (untranslated) text" toggle (#143).
|
||||
const showOrig = reactive({})
|
||||
function toggleOrig(id) { showOrig[id] = !showOrig[id] }
|
||||
watch(() => effectiveId.value, () => {
|
||||
for (const k of Object.keys(expanded)) delete expanded[k]
|
||||
for (const k of Object.keys(showOrig)) delete showOrig[k]
|
||||
})
|
||||
|
||||
watch(
|
||||
@@ -157,10 +171,23 @@ const show = computed(() => {
|
||||
const attachments = computed(() => state.value?.attachments || [])
|
||||
|
||||
function postDate(e) { return formatPostDate(e.post.date) }
|
||||
// Translation-forward (#143): show the English by default when present.
|
||||
function hasTranslation(e) {
|
||||
return !!(e.post.title_translated || e.post.description_translated)
|
||||
}
|
||||
function showTranslated(e) {
|
||||
return hasTranslation(e) && !showOrig[e.provenance_id]
|
||||
}
|
||||
function langLabel(e) {
|
||||
return e.post.translated_source_lang ? ` (${e.post.translated_source_lang})` : ''
|
||||
}
|
||||
function postTitle(e) {
|
||||
// Titles can arrive as stored HTML (e.g. "<strong>…</strong>"); render
|
||||
// as plain text (the CSS makes it bold).
|
||||
return toPlainText(e.post.title) || `Post ${e.post.external_post_id}`
|
||||
const t = showTranslated(e) && e.post.title_translated
|
||||
? e.post.title_translated
|
||||
: e.post.title
|
||||
return toPlainText(t) || `Post ${e.post.external_post_id}`
|
||||
}
|
||||
|
||||
function openPost(postId, artistId) {
|
||||
|
||||
Reference in New Issue
Block a user