diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b9ae480af..2cbe412202 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ - Fix: ユーザーのプロフィール画面をアドレス入力などで直接表示した際に概要タブの描画に失敗する問題の修正( #15032 ) - Fix: 起動前の疎通チェックが機能しなくなっていた問題を修正 (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/737) +- Fix: 非Misskey系のソフトウェアからHTML``タグを含むノートを受信した場合、MFMの読み仮名(ルビ)文法に変換して表示 ## 2024.11.0 diff --git a/packages/backend/src/core/MfmService.ts b/packages/backend/src/core/MfmService.ts index 8061622340..bf06d4457e 100644 --- a/packages/backend/src/core/MfmService.ts +++ b/packages/backend/src/core/MfmService.ts @@ -171,6 +171,39 @@ export class MfmService { break; } + case 'ruby': { + let ruby: [string, string][] = []; + for (const child of node.childNodes) { + if (child.nodeName === 'rp') { + continue; + } + if (treeAdapter.isTextNode(child) && !/\s|\[|\]/.test(child.value)) { + ruby.push([child.value, '']); + continue; + } + if (child.nodeName === 'rt' && ruby.length > 0) { + const rt = getText(child); + if (/\s|\[|\]/.test(rt)) { + // If any space is included in rt, it is treated as a normal text + ruby = []; + appendChildren(node.childNodes); + break; + } else { + ruby.at(-1)![1] = rt; + continue; + } + } + // If any other element is included in ruby, it is treated as a normal text + ruby = []; + appendChildren(node.childNodes); + break; + } + for (const [base, rt] of ruby) { + text += `$[ruby ${base} ${rt}]`; + } + break; + } + // block code (
)
 				case 'pre': {
 					if (node.childNodes.length === 1 && node.childNodes[0].nodeName === 'code') {
diff --git a/packages/backend/test/unit/MfmService.ts b/packages/backend/test/unit/MfmService.ts
index fd4a03413b..36af8823f6 100644
--- a/packages/backend/test/unit/MfmService.ts
+++ b/packages/backend/test/unit/MfmService.ts
@@ -108,6 +108,24 @@ describe('MfmService', () => {
 			assert.deepStrictEqual(mfmService.fromHtml('

a d

'), 'a d'); }); + test('ruby', () => { + assert.deepStrictEqual(mfmService.fromHtml('

a Misskey(ミスキー) b

'), 'a $[ruby Misskey ミスキー] b'); + assert.deepStrictEqual(mfmService.fromHtml('

a Misskey(ミスキー)Misskey(ミスキー) b

'), 'a $[ruby Misskey ミスキー]$[ruby Misskey ミスキー] b'); + }); + + test('ruby with spaces', () => { + assert.deepStrictEqual(mfmService.fromHtml('

a Miss key(ミスキー) b c

'), 'a Miss key(ミスキー) b c'); + assert.deepStrictEqual(mfmService.fromHtml('

a Misskey(ミス キー) b c

'), 'a Misskey(ミス キー) b c'); + assert.deepStrictEqual( + mfmService.fromHtml('

a Misskey(ミスキー)Misskey(ミス キー)Misskey(ミスキー) b

'), + 'a Misskey(ミスキー)Misskey(ミス キー)Misskey(ミスキー) b' + ); + }); + + test('ruby with other inline tags', () => { + assert.deepStrictEqual(mfmService.fromHtml('

a Misskey(ミスキー) b c

'), 'a **Misskey**(ミスキー) b c'); + }); + test('mention', () => { assert.deepStrictEqual(mfmService.fromHtml('

a @user d

'), 'a @user@example.com d'); });