Changeset 0688b5f in Klonkt for src/services


Ignore:
Timestamp:
07/01/2026 07:06:45 PM (2 months ago)
Author:
roboburr <roboburr@…>
Branches:
main
Children:
1c2dcba
Parents:
d18c60e
Message:

feat(fediverse): post language → AS2 contentMap

A post can now carry a language; it federates as an AS2 contentMap (a BCP-47-keyed
copy of the content, alongside plain content) so Mastodon's timeline language filter
and translate button work. Editor gets a language picker (defaults to the author's
UI language).

  • src/config/database.js — posts.language column.
  • src/services/ActivityPubService.js — buildNote emits contentMap { <lang>: content } when the post has a valid BCP-47 language.
  • src/routes/posts.js — capture/validate/store language on create/save (default = the author's current language) and pass it to the federation hooks.
  • src/services/Scheduler.js — carry language when a scheduled post goes live.
  • src/views/pages/post-edit.ejs — language <select> (18 common languages).
  • src/services/i18n.js — pedit.f_language + pedit.language_hint (nl/en/de).
  • test/activitypub-as2.test.js — allow contentMap/nameMap/summaryMap; don't treat a language-map's keys as vocab terms; kitchen-sink post now sets a language.
  • test/post-language.test.js — contentMap shape, no-language, invalid-code = ignored.
  • CHANGELOG(.nl/.de).md — "Set a post's language" under Unreleased.

Co-Authored-By: Claude <noreply@…>

Location:
src/services
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • src/services/ActivityPubService.js

    rd18c60e r0688b5f  
    400400  // make it JSON-LD-clean with a context term, otherwise it degrades to the player card.
    401401  if (playable) note.embedUrl = `${base}/embed?post=${encodeURIComponent(post.slug)}`;
     402  // Content language → AS2 contentMap (a BCP-47-keyed copy of the content). Mastodon reads the
     403  // language from its key for the timeline language filter + the translate button. Emitted
     404  // alongside `content` (Mastodon sends both); a plain receiver just uses `content`.
     405  if (post.language && /^[a-z]{2,3}(-[A-Za-z]{2,4})?$/.test(post.language)) note.contentMap = { [post.language]: note.content };
    402406  // A hosted poll → federate as an AS2 Question (options + live tally). Do this last so it
    403407  // reuses the note's content/addressing/tags, then swaps the type and strips media.
  • src/services/Scheduler.js

    rd18c60e r0688b5f  
    1515  try {
    1616    const due = db.prepare(`
    17       SELECT p.id, p.site_id, p.slug, p.title, p.content, p.cover_image_url, p.cover_video_url, p.cover_alt, p.fan_only, p.nsfw, p.content_warning, p.poll_json,
     17      SELECT p.id, p.site_id, p.slug, p.title, p.content, p.cover_image_url, p.cover_video_url, p.cover_alt, p.language, p.fan_only, p.nsfw, p.content_warning, p.poll_json,
    1818             p.published_at, p.publish_at, p.created_at, u.username
    1919      FROM posts p JOIN users u ON u.id = p.author_id
     
    3838          ActivityPubService.deliverCreate(site, {
    3939            id: p.id, slug: p.slug, title: p.title || p.slug,
    40             content: p.content, cover_image_url: p.cover_image_url || null, cover_video_url: p.cover_video_url || null, cover_alt: p.cover_alt,
     40            content: p.content, cover_image_url: p.cover_image_url || null, cover_video_url: p.cover_video_url || null, cover_alt: p.cover_alt, language: p.language,
    4141            published_at: p.published_at || p.publish_at, created_at: p.created_at, fan_only: p.fan_only, nsfw: p.nsfw, content_warning: p.content_warning, poll_json: p.poll_json,
    4242          }).catch(() => { /* best-effort */ });
  • src/services/i18n.js

    rd18c60e r0688b5f  
    639639    'pedit.f_cover_alt': 'Alt-tekst (beschrijving)',
    640640    'pedit.cover_alt_placeholder': 'Beschrijf de afbeelding voor schermlezers',
     641    'pedit.f_language': 'Taal',
     642    'pedit.language_hint': 'voor het fediverse-taalfilter',
    641643    'pedit.cover_upload_btn': 'Upload nieuwe cover',
    642644    'pedit.s_content': 'Content',
     
    15591561    'pedit.f_cover_alt': 'Alt text (description)',
    15601562    'pedit.cover_alt_placeholder': 'Describe the image for screen readers',
     1563    'pedit.f_language': 'Language',
     1564    'pedit.language_hint': 'for the fediverse language filter',
    15611565    'pedit.cover_upload_btn': 'Upload new cover',
    15621566    'pedit.s_content': 'Content',
     
    24792483    'pedit.f_cover_alt': 'Alt-Text (Beschreibung)',
    24802484    'pedit.cover_alt_placeholder': 'Beschreibe das Bild für Screenreader',
     2485    'pedit.f_language': 'Sprache',
     2486    'pedit.language_hint': 'für den Fediverse-Sprachfilter',
    24812487    'pedit.cover_upload_btn': 'Neues Titelbild hochladen',
    24822488    'pedit.s_content': 'Inhalt',
Note: See TracChangeset for help on using the changeset viewer.