You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

72 lines
2.2 KiB

import type { Event } from 'nostr-tools'
import { useSyncExternalStore } from 'react'
export type NoteTranslationEntry = {
/** LibreTranslate `target` code (from `/languages`). */
lang: string
/** Human label from the translate service (read-aloud fallback when not an app UI locale). */
langLabel?: string
content: string
/** When present, replaces or inserts a `title` tag (articles, discussions, web bookmarks). */
title?: string
/**
* Related notes (parent preview, embedded) translated in the same action as this note.
* Cleared together when the user chooses “show original” on this note.
*/
coTranslatedIds?: string[]
}
const map = new Map<string, NoteTranslationEntry>()
const listeners = new Set<() => void>()
function emit(): void {
listeners.forEach((l) => l())
}
export function subscribeNoteTranslations(onStoreChange: () => void): () => void {
listeners.add(onStoreChange)
return () => listeners.delete(onStoreChange)
}
export function setNoteTranslation(eventId: string, entry: NoteTranslationEntry): void {
map.set(eventId, entry)
emit()
}
export function clearNoteTranslation(eventId: string): void {
const entry = map.get(eventId)
if (entry?.coTranslatedIds?.length) {
for (const id of entry.coTranslatedIds) {
map.delete(id)
}
}
map.delete(eventId)
emit()
}
export function getNoteTranslation(eventId: string): NoteTranslationEntry | undefined {
return map.get(eventId)
}
export function useNoteTranslation(eventId: string): NoteTranslationEntry | undefined {
return useSyncExternalStore(
subscribeNoteTranslations,
() => map.get(eventId),
() => map.get(eventId)
)
}
function patchTitleInTagsCopy(tags: string[][], title: string): string[][] {
const out = tags.map((row) => row.slice())
const i = out.findIndex((r) => r[0] === 'title')
if (i >= 0) out[i] = ['title', title]
else out.unshift(['title', title])
return out
}
/** Event with translated `content` / optional `title` tag for body renderers. */
export function mergeTranslatedNote(event: Event, tr?: NoteTranslationEntry | null): Event {
if (!tr) return event
const tags = tr.title ? patchTitleInTagsCopy(event.tags, tr.title) : event.tags
return { ...event, content: tr.content, tags }
}