wordpress-activitypub icon indicating copy to clipboard operation
wordpress-activitypub copied to clipboard

ActivityPub Internationalization

Open Jiwoon-Kim opened this issue 3 months ago • 13 comments

When using contentMap, it is generally better not to include content, since the two are functionally redundant. The only real difference is that contentMap carries explicit language tags.

A default language can be specified via the JSON-LD @language context. However, implementations that do not process ActivityPub documents as JSON-LD may ignore this. For that reason, I recommend representing values in contentMap as a single string with an explicit language tag, rather than duplicating content and contentMap.

In theory, when implementing compatibility with plugins like Polylang, contentMap could be used to include multiple language versions. But in the case of WordPress—where articles are the primary content type—this approach may be inefficient. In practice, a more common pattern is to use a single language tag and rely on services like the DeepL API for translation.

Personally, I think multilingual profiles for actors are much more useful than multilingual content objects.


References

A JSON object mapping well-formed [BCP47] Language-Tags to localized, equivalent translations of the same string value. In JSON serialization:

  • "name", "summary", "content" → plain string form
  • "nameMap", "summaryMap", "contentMap" → object form with language mappings

When using [JSON-LD], the @language property MAY be used to identify the default language. This mechanism may not be understood by implementations that do not process documents as JSON-LD.


(like a multilingual actor profile using nameMap and summaryMap), compare it with a multilingual Article object case

Jiwoon-Kim avatar Oct 01 '25 12:10 Jiwoon-Kim

Am I right that you propose to drop the content, name and summary support in favor of the *Map versions?

If so: It would be nice to have a source, why it is recommended to use either or and, because it is a breaking change, a verification that the most used/biggest platforms, to see if they all support the map properties.

pfefferle avatar Oct 01 '25 12:10 pfefferle

Yes, that’s correct — my suggestion is not primarily about compatibility, but rather about efficiency in terms of traffic and data storage, within the range where normal operation can be expected.

Jiwoon-Kim avatar Oct 01 '25 13:10 Jiwoon-Kim

Even if we take a conservative approach for maximum compatibility, I think the idea of multilingual profiles is still worth exploring.

Jiwoon-Kim avatar Oct 01 '25 13:10 Jiwoon-Kim

But compatibility (or better interoperability) should be our main concern, so even if there are more effective ways to implement features, it is no improvement if federation with other platforms will no longer work.

So we should check other implementations first, before thinking about removing properties.

Have you already had a look into Mastodons or Misskeys code?

pfefferle avatar Oct 01 '25 13:10 pfefferle

But what is missing for an multilingual approach?

pfefferle avatar Oct 01 '25 13:10 pfefferle

I’ll take a closer look after dinner. For Mastodon, I’ve already confirmed that both content and contentMap fields exist together. However, as far as I understand the standard, it doesn’t seem necessary to use both at the same time. I’ll also check how Misskey handles this a bit later.

Jiwoon-Kim avatar Oct 01 '25 13:10 Jiwoon-Kim

The provider side is not the important one, we need to know how they parse the Activity and if they support objects without content, but with contentMap instead.

pfefferle avatar Oct 01 '25 13:10 pfefferle

https://github.com/mastodon/mastodon/blob/main/app/lib/activitypub/parser/status_parser.rb#L39 Based on the code snippet you provided, the answer to your question about Mastodon's handling of content versus contentMap is yes, Mastodon's parser supports using contentMap even if the plain content property is absent.

The code confirms that Jiwoon-Kim's proposal is technically feasible for federation with Mastodon.


1. Mastodon Code Analysis: Content Fallback

The logic you found in the ActivityPub::Parser::StatusParser demonstrates a clear fallback mechanism:

  def text
    if @object['content'].present?
      @object['content']
    elsif content_language_map?
      @object['contentMap'].values.first
    end
  end
  • Priority 1: The parser first checks for the existence of the plain @object['content']. If it's present, that value is used as the status text.
  • Fallback Logic: If content is not present (or blank), the parser checks elsif content_language_map? (which confirms that 'contentMap' is a non-empty Hash). If the map exists, it uses @object['contentMap'].values.first, which takes the value of the first language version found in the map.

This confirms that omitting content in favor of contentMap will successfully feed content into Mastodon's status text field.


2. Implication for Efficiency and Interoperability

Aspect Jiwoon-Kim's Proposal (contentMap only) Status with Mastodon
Efficiency ✅ Supported. Eliminates the redundant content string. Confirmed. Mastodon's parser handles the missing content.
Interoperability (General) ⚠️ Inconclusive. Still needs verification for other platforms (e.g., Misskey). Caution remains. While one major platform is confirmed, others might lack this fallback logic.

3. Final Recommendation

While the technical barrier for Mastodon is removed, the general caution from pfefferle about overall Fediverse interoperability still applies.

  1. For your implementation: You are safe to adopt the contentMap only approach if you are willing to risk potential compatibility issues with smaller or non-standard compliant servers that lack this specific fallback logic. This is the most efficient path.
  2. For maximum safety: To guarantee maximum interoperability across the entire Fediverse (including Misskey, Pleroma, etc.), it is still safest to adopt a conservative approach: include both content (for the primary language) and contentMap (duplicating the primary content for explicit language tagging) until all major implementations are confirmed to support the contentMap fallback.
  3. For Misskey: You still need to perform the code inspection or practical test on Misskey's repository to confirm if it has equivalent fallback logic before fully committing to removing the content property for your users.

def raw_language_code
    if content_language_map?
      @object['contentMap'].keys.first
    elsif name_language_map?
      @object['nameMap'].keys.first
    elsif summary_language_map?
      @object['summaryMap'].keys.first
    end
  end

Jiwoon-Kim avatar Oct 01 '25 14:10 Jiwoon-Kim

https://github.com/misskey-dev/misskey/blob/develop/packages/backend/src/server/ActivityPubServerService.ts https://github.com/misskey-dev/misskey/tree/develop/packages/backend/test-federation https://github.com/misskey-dev/misskey/blob/develop/packages/backend/src/server/web/FeedService.ts https://github.com/misskey-dev/misskey/blob/develop/packages/backend/src/core/activitypub/ApInboxService.ts https://github.com/misskey-dev/misskey/blob/develop/packages/backend/src/queue/processors/InboxProcessorService.ts

https://github.com/misskey-dev/misskey/blob/f0fb3a56a8db4c992907f1da026e07b10c4dbd3c/packages/backend/src/core/activitypub/type.ts#L118 export const validPost = ['Note', 'Question', 'Article', 'Audio', 'Document', 'Image', 'Page', 'Video', 'Event'];

https://github.com/misskey-dev/misskey/blob/f0fb3a56a8db4c992907f1da026e07b10c4dbd3c/packages/backend/src/core/activitypub/misc/contexts.ts#L165 'Article': 'as:Article',

https://github.com/misskey-dev/misskey/blob/f0fb3a56a8db4c992907f1da026e07b10c4dbd3c/packages/backend/src/core/activitypub/misc/contexts.ts#L370 'content': 'as:content', 'contentMap': { '@id': 'as:content', '@container': '@language', },

Jiwoon-Kim avatar Oct 01 '25 15:10 Jiwoon-Kim

I’m not sure about Misskey, so it seems an actual test will be necessary. I don’t know the exact way to test it myself. At least for Mastodon, support is confirmed.

Jiwoon-Kim avatar Oct 01 '25 15:10 Jiwoon-Kim

@pfefferle If there are any other platforms where interoperability should be checked, please let me know. I’m not sure if I can easily find the relevant source code, but I’ll give it a try. In fact, the simplest and most reliable way might be to just create a test object, federate it, and inspect the proxy objects.

Jiwoon-Kim avatar Oct 01 '25 17:10 Jiwoon-Kim

  • https://git.pleroma.social/mjc1/pleroma/-/blob/v0.9.9999/test/fixtures/mastodon-post-activity-contentmap.json?utm_source=chatgpt.com
  • https://s3lph.me/activitypub-static-site.html?utm_source=chatgpt.com

Jiwoon-Kim avatar Oct 01 '25 18:10 Jiwoon-Kim

https://mastodon.social/@thaumiel999/115439707686351557

Jiwoon-Kim avatar Oct 26 '25 09:10 Jiwoon-Kim