memi-board 0.44.0 → 0.45.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/README.md +54 -3
  2. package/dist/ar-BCQdRw_S.js +622 -0
  3. package/dist/ar-BCQdRw_S.js.map +1 -0
  4. package/dist/composables/fetchPublicSeo.d.ts +4 -1
  5. package/dist/composables/useMemiBoardAutoTranslate.d.ts +33 -0
  6. package/dist/composables/useMemiBoardModeration.d.ts +5 -1
  7. package/dist/composables/useMemiBoardReports.d.ts +6 -1
  8. package/dist/composables/useMemiBoardSections.d.ts +2 -1
  9. package/dist/composables/useMemiBoardUsers.d.ts +4 -0
  10. package/dist/composables/useMemiBoardWritingAssistant.d.ts +9 -1
  11. package/dist/config.d.ts +5 -0
  12. package/dist/de-ddWQNaqs.js +622 -0
  13. package/dist/de-ddWQNaqs.js.map +1 -0
  14. package/dist/en-BVUBLkxc.js +648 -0
  15. package/dist/en-BVUBLkxc.js.map +1 -0
  16. package/dist/es-7JHjGVlM.js +622 -0
  17. package/dist/es-7JHjGVlM.js.map +1 -0
  18. package/dist/fr-C3NCMNoy.js +622 -0
  19. package/dist/fr-C3NCMNoy.js.map +1 -0
  20. package/dist/id-C8hCAMPJ.js +622 -0
  21. package/dist/id-C8hCAMPJ.js.map +1 -0
  22. package/dist/index.d.ts +10 -1
  23. package/dist/index.js +1218 -1487
  24. package/dist/index.js.map +1 -1
  25. package/dist/ja-oTWri4hY.js +622 -0
  26. package/dist/ja-oTWri4hY.js.map +1 -0
  27. package/dist/module.mjs +55 -31
  28. package/dist/module.mjs.map +1 -1
  29. package/dist/pt-B9EH4scA.js +622 -0
  30. package/dist/pt-B9EH4scA.js.map +1 -0
  31. package/dist/runtime/components/Attachments.vue +4 -2
  32. package/dist/runtime/components/AuthorMenu.vue +14 -12
  33. package/dist/runtime/components/AvatarCropModal.vue +8 -5
  34. package/dist/runtime/components/CategorySettings.vue +65 -43
  35. package/dist/runtime/components/CommentFeed.vue +9 -7
  36. package/dist/runtime/components/CommentForm.vue +16 -10
  37. package/dist/runtime/components/CommentItem.vue +25 -26
  38. package/dist/runtime/components/CommentList.vue +7 -4
  39. package/dist/runtime/components/CommentThread.vue +7 -5
  40. package/dist/runtime/components/Detail.vue +20 -15
  41. package/dist/runtime/components/Editor.vue +145 -135
  42. package/dist/runtime/components/Footer.vue +14 -13
  43. package/dist/runtime/components/List.vue +31 -29
  44. package/dist/runtime/components/ListDefault.vue +4 -3
  45. package/dist/runtime/components/ListDense.vue +6 -5
  46. package/dist/runtime/components/ListImage.vue +4 -2
  47. package/dist/runtime/components/ListVideo.vue +3 -2
  48. package/dist/runtime/components/ListViewSwitch.vue +10 -6
  49. package/dist/runtime/components/MiniCard.vue +3 -2
  50. package/dist/runtime/components/MiniComments.vue +5 -4
  51. package/dist/runtime/components/MiniList.vue +3 -2
  52. package/dist/runtime/components/MiniPicker.vue +10 -9
  53. package/dist/runtime/components/MiniPost.vue +3 -2
  54. package/dist/runtime/components/MiniPosts.vue +5 -4
  55. package/dist/runtime/components/Profile.vue +12 -7
  56. package/dist/runtime/components/ProfileEditModal.vue +14 -13
  57. package/dist/runtime/components/ReportButton.vue +20 -10
  58. package/dist/runtime/components/ReportList.vue +11 -10
  59. package/dist/runtime/components/Section.vue +3 -2
  60. package/dist/runtime/components/Settings.vue +84 -62
  61. package/dist/runtime/components/ShareButton.vue +3 -1
  62. package/dist/runtime/components/SignIn.vue +14 -8
  63. package/dist/runtime/components/SwipeHint.vue +5 -3
  64. package/dist/runtime/components/UserCommentList.vue +8 -6
  65. package/dist/runtime/components/UserPostList.vue +6 -4
  66. package/dist/runtime/components/Users.vue +16 -10
  67. package/dist/runtime/composables/useMemiBoardSeo.ts +16 -10
  68. package/dist/slugify-6bG6GSO_.js +942 -0
  69. package/dist/slugify-6bG6GSO_.js.map +1 -0
  70. package/dist/storage.js +72 -71
  71. package/dist/storage.js.map +1 -1
  72. package/dist/types.d.ts +4 -0
  73. package/dist/utils/boardSeo.d.ts +5 -5
  74. package/dist/utils/compressImage.d.ts +2 -1
  75. package/dist/utils/formatDate.d.ts +6 -4
  76. package/dist/utils/imeSafeSubmit.d.ts +2 -0
  77. package/dist/utils/moderation-prompt.d.ts +18 -1
  78. package/dist/utils/moderation-strike.d.ts +2 -1
  79. package/dist/utils/section.d.ts +15 -2
  80. package/dist/zh-D5rDYV6E.js +622 -0
  81. package/dist/zh-D5rDYV6E.js.map +1 -0
  82. package/package.json +2 -3
  83. package/dist/slugify-Cm_pi2al.js +0 -124
  84. package/dist/slugify-Cm_pi2al.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ja-oTWri4hY.js","names":[],"sources":["../src/i18n/messages/ja.ts"],"sourcesContent":["import type { MemiBoardMessages } from '../translate'\n\n/** 짧은 화면 문구만 번역한다. 빠진 키는 en → ko 순으로 폴백된다. */\nconst messages: MemiBoardMessages = {\n attachments: {\n attach: 'ファイルを添付({count} / {max})',\n maxFiles: '最大{max}件まで添付できます。',\n },\n auth: {\n writeRestricted: 'コンテンツ警告が累積したため、投稿・コメントが一時的に制限されています。',\n strikeSuffix: '(警告 {count}/{threshold})',\n strikeRestricted: '警告が{count}回に達したため、投稿・コメントが制限されます。',\n notInitialized: '[memi-board] Firebase Authが初期化されていません。',\n },\n authorMemo: {\n tooLong: 'メモは{max}文字まで入力できます。',\n },\n authorMenu: {\n viewProfile: 'プロフィールを見る',\n viewPosts: '投稿を見る',\n viewComments: 'コメントを見る',\n memoAriaLabel: 'この投稿者についてのメモ',\n memoTitle: '自分だけのメモ',\n memoPlaceholder: 'この投稿者についてメモする…',\n bad: '悪い',\n good: '良い',\n },\n avatarCropModal: {\n title: 'プロフィール写真を切り抜き',\n description: '正方形(1:1)で表示されます。範囲を調整してください。',\n confirm: '切り抜いてアップロード',\n },\n boardSettings: {\n signInRequired: 'ログインが必要です。',\n idAndNameRequired: 'ボードIDと名前を入力してください。',\n deleteIdRequired: '削除する掲示板のIDが必要です。',\n nameRequired: 'ボード名を入力してください。',\n },\n boardUsers: {\n unsupportedRole: 'サポートされていないロールです。',\n roleDescription: {\n admin: 'ユーザーのロール、掲示板の設定、すべてのコンテンツを管理します。',\n user: '投稿とコメントができ、自分のコンテンツのみ編集・削除できます。',\n },\n },\n commentFeed: {\n empty: 'まだコメントはありません。',\n emptyLiked: 'いいねされたコメントはまだありません。',\n loadFailed: '一覧を読み込めませんでした: {error}',\n blinded: '管理者により非表示にされたコメントです。',\n },\n commentForm: {\n hiddenBoardDenied: '非表示の掲示板には担当スタッフのみコメントできます。',\n denied: 'この掲示板にコメントする権限がありません。',\n signInRequired: 'ログインが必要です。',\n writeRestricted: 'コンテンツ警告が累積したため、投稿・コメントが一時的に制限されています。',\n moderationBlocked: '投稿できない内容が含まれています。',\n replyTo: '{name}さんに返信',\n placeholder: 'コメントを入力',\n submitReply: '返信する',\n submit: 'コメントする',\n signInToComment: 'コメントするにはログインが必要です。',\n },\n commentItem: {\n editRestricted: 'コメントの編集が一時的に制限されています。',\n moderationBlocked: '投稿できない内容が含まれています。',\n editFailed: 'コメントを編集できませんでした。',\n blindFailed: '非表示の状態を変更できませんでした。',\n likeFailed: 'いいねを処理できませんでした。',\n blinded: '管理者により非表示にされたコメントです。',\n edit: 'コメントを編集',\n blind: 'コメントを非表示',\n unblind: 'コメントの非表示を解除',\n delete: 'コメントを削除',\n },\n commentList: {\n loading: 'コメントを読み込んでいます',\n empty: 'まだコメントはありません。',\n loadMore: 'コメントをもっと見る',\n loadingMore: 'コメントをさらに読み込んでいます',\n },\n commentThread: {\n deleteConfirm: 'このコメントを削除しますか?',\n deleteFailed: 'コメントを削除できませんでした。',\n hideReplies: '返信を非表示',\n showReplies: '返信{count}件',\n loadMoreReplies: '返信をもっと見る',\n },\n comments: {\n bodyRequired: 'コメントを入力してください。',\n bodyTooLong: 'コメントは{max}文字まで入力できます。',\n replyTargetNotFound: '返信先のコメントが見つかりません。',\n threadNotFound: 'コメントスレッドが見つかりません。',\n hasRepliesCannotDelete: '返信があるコメントは現在削除できません。',\n },\n common: {\n action: {\n cancel: 'キャンセル',\n save: '保存',\n saved: '保存済み',\n edit: '編集',\n delete: '削除',\n confirm: 'OK',\n close: '閉じる',\n add: '追加',\n more: 'もっと見る',\n prev: '前へ',\n next: '次へ',\n retry: '再試行',\n reply: '返信',\n like: 'いいね',\n unlike: 'いいねを取り消す',\n share: '共有',\n report: '通報',\n signIn: 'ログイン',\n signOut: 'ログアウト',\n write: '投稿する',\n toTop: 'トップへ',\n },\n label: {\n anonymous: '匿名',\n user: 'ユーザー',\n image: '画像',\n draft: '下書き',\n loading: '読み込み中…',\n },\n role: {\n admin: '管理者',\n staff: 'スタッフ',\n user: 'ユーザー',\n },\n date: {\n justNow: 'たった今',\n fewSecondsAgo: '数秒前',\n checking: '時刻を確認中',\n createdAt: '作成日時: {time}',\n updatedAt: '更新日時: {time}',\n },\n },\n detail: {\n deleteConfirm: 'この投稿を削除しますか?元に戻すことはできません。',\n notFound: '投稿が見つかりません。',\n draftPreview: '非公開プレビュー',\n draftNotice: 'まだ公開されていません。公開するまでは投稿者だけが閲覧できます。',\n publish: '公開する',\n backToList: '一覧に戻る',\n postNav: '投稿の移動',\n list: '一覧',\n comments: 'コメント',\n },\n editor: {\n titlePlaceholder: 'タイトル',\n contentPlaceholder: '本文を入力…「/」でブロックメニューが開きます。',\n imageContentPlaceholder: '内容を入力…',\n tagsPlaceholder: 'タグを入力してEnter',\n skipModeration: '不適切表現フィルターを無視(管理者)',\n submitEdit: '編集を完了',\n submitNext: '次へ: プレビュー',\n apply: '適用',\n imageOptimizing: '画像を最適化してアップロード中…',\n cover: {\n imageLink: '画像リンク',\n addPhoto: '写真を追加',\n alt: '写真{n}',\n representative: 'カバー',\n setRepresentative: 'カバーに設定',\n setRepresentativeAria: '写真{n}をカバー写真に設定',\n remove: '写真を削除',\n add: '追加',\n uploading: 'アップロード中…',\n dropOrClick: '写真をドロップまたはクリックして追加',\n emptyHint: '複数選択可 · アップロード後にカバー写真を選択 · ドラッグで並べ替え',\n uploadTitle: 'アップロード',\n },\n uploadFailed: 'アップロード失敗',\n aiAssistant: 'AI文章アシスタント',\n insertBlock: 'ブロックを挿入',\n blockMenu: 'ブロックメニュー',\n imageDialog: {\n title: '画像を追加',\n chooseFile: 'デバイスから画像を選択',\n orLink: 'または画像リンク',\n urlLabel: '画像URL',\n previewAlt: '外部画像のプレビュー',\n addLink: 'リンクを追加',\n },\n customDialog: {\n title: 'カスタムスタイルに書き換え',\n label: 'どのように書き換えますか?',\n help: '例: 関西弁で / 丁寧な書き言葉で / 簡潔な箇条書きで',\n placeholder: '関西弁で',\n },\n aiPreview: {\n title: 'AIの結果を確認',\n currentTitle: '現在のタイトル',\n newTitle: '新しいタイトル',\n currentContent: '現在の内容',\n appendedContent: '追加される内容',\n before: '変更前',\n after: '変更後',\n },\n menu: {\n ai: 'AI',\n aiContinue: 'AIで続きを書く',\n style: 'スタイル',\n insert: '挿入',\n paragraph: '本文',\n heading1: '見出し1',\n heading2: '見出し2',\n heading3: '見出し3',\n bulletList: '箇条書きリスト',\n orderedList: '番号付きリスト',\n blockquote: '引用',\n codeBlock: 'コードブロック',\n horizontalRule: '区切り線',\n image: '画像',\n turnInto: 'ブロックの種類を変更',\n resetFormatting: '書式をリセット',\n duplicate: '複製',\n moveUp: '上に移動',\n moveDown: '下に移動',\n delete: '削除',\n },\n toolbar: {\n link: 'リンク',\n image: '画像',\n format: '書式',\n bold: '太字',\n italic: '斜体',\n underline: '下線',\n strike: '取り消し線',\n title: 'タイトル',\n heading: '見出し',\n subheading: '小見出し',\n body: '本文',\n mono: '等幅',\n bulletList: '箇条書きリスト',\n orderedList: '番号付きリスト',\n blockquote: 'ブロック引用',\n codeBlock: 'コードブロック',\n horizontalRule: '区切り線',\n clearFormatting: '書式をクリア',\n undo: '元に戻す',\n redo: 'やり直す',\n },\n ai: {\n proofread: 'スペルチェック',\n polish: '文章を整える',\n continue: '自然に続きを書く',\n summarize: '短く要約',\n translateEn: '英語に翻訳',\n translateKo: '韓国語に翻訳',\n title: '本文からタイトルを生成',\n custom: 'カスタムスタイルに書き換え…',\n failed: 'AI処理に失敗しました。もう一度お試しください。',\n },\n youtubePrompt: 'YouTubeのリンクを入力してください。',\n errors: {\n coverMax: '写真は最大{max}枚までアップロードできます。',\n imageUrlRequired: '画像のURLを入力してください。',\n imageUrlInvalid: '正しい画像URLを入力してください。',\n imageUrlHttps: 'HTTPSの画像URLのみ使用できます。',\n imageUrlCredentials: 'ログイン情報を含むURLは使用できません。',\n imageTimeout: '画像の読み込みに時間がかかりすぎています。',\n imageNotDisplayable: '表示できない画像です。',\n editorNotReady: 'エディターを準備できませんでした。もう一度お試しください。',\n imageLinkFailed: '画像リンクを追加できませんでした。',\n imageOnly: '画像ファイルのみアップロードできます。',\n imageTooLarge: '元の画像は{mb}MB以下にしてください。',\n imageUploadFailed: '画像のアップロードに失敗しました。',\n pasteAsFile: '写真はファイルとして上のエリアに貼り付けるか、ドラッグしてください。',\n postNotFound: '投稿が見つかりません。',\n loadPermission: '投稿を読み込む権限がありません。ログイン状態を確認してください。',\n loadFailed: '投稿を読み込めませんでした: {message}',\n titleRequired: 'タイトルを入力してください。',\n photoRequired: '写真を1枚以上アップロードしてください。',\n bodyRequired: '本文にテキストを入力するか、画像を添付してください。',\n signInRequired: 'ログインが必要です。',\n boardMissing: '掲示板(ボード)が指定されていません。',\n writeRestricted: 'コンテンツ警告が累積したため、投稿・コメントが一時的に制限されています。',\n moderationBlocked: '投稿できない内容が含まれています。',\n },\n hint: {\n reviewing: '内容を確認中…',\n saving: '保存中…',\n },\n },\n footer: {\n info: {\n title: '掲示板の情報',\n about: 'この掲示板について',\n history: 'バージョン履歴',\n },\n stack: {\n ui: '画面と操作性',\n data: 'データとログイン',\n writing: '執筆と便利機能',\n },\n },\n likes: {\n signInRequired: 'ログインが必要です。',\n commentNotFound: 'コメントが見つかりません。',\n },\n list: {\n settings: '設定',\n loadFailed: '一覧を読み込めませんでした: {error}',\n empty: 'まだ投稿はありません。',\n photo: '写真',\n likeCount: 'いいね {count}',\n info: {\n title: '掲示板の情報',\n about: 'この掲示板について',\n history: 'バージョン履歴',\n },\n stack: {\n framework: 'フレームワーク & 言語',\n ui: 'UI & スタイル',\n backend: 'バックエンド & データ',\n },\n tech: {\n nuxt: 'VueベースのSSRフレームワーク',\n vue: 'Composition API · script setup',\n typescript: '安全なデータとコンポーネントの型',\n nuxtUi: '掲示板・フォーム・モーダルのUI',\n tailwind: 'レスポンシブ · ライト/ダークスタイル',\n lucide: '軽量で統一感のあるアイコン',\n dayjs: '読みやすい日付と相対時刻',\n firestore: '投稿とコメントのためのリアルタイムDB',\n auth: '安全なログインと権限管理',\n storage: '画像と添付ファイルの保存',\n vuefire: 'NuxtとFirebaseのリアルタイム連携',\n },\n },\n listViewSwitch: {\n default: '標準',\n dense: 'コンパクト',\n video: '動画',\n },\n miniComments: {\n empty: 'まだコメントはありません。',\n blinded: '管理者により非表示にされたコメントです。',\n },\n miniList: {\n empty: 'まだ投稿はありません。',\n },\n miniPicker: {\n selectedCount: '選択した投稿 {count} / {max}',\n layoutHint: '2件以上でカルーセル、4件でグリッド',\n searchPlaceholder: 'タイトルを検索',\n loading: '投稿を読み込み中…',\n noMore: '選択できる投稿はもうありません。',\n },\n miniPost: {\n empty: '選択された投稿はありません。',\n },\n moderation: {\n writeRestricted: 'コンテンツ警告が累積したため、投稿・コメントが一時的に制限されています。',\n },\n moderationPrompt: {\n localHit: '「{hit}」のような表現は使用できません。別の言葉に言い換えてください。',\n localGeneric: '暴言・卑語が含まれているため投稿できません。表現を変えてください。',\n genericBlocked: '投稿できない内容が含まれています。内容を修正してください。',\n categories: {\n abuse: '暴言・卑語・侮辱',\n spam: 'スパム・広告',\n adult: '性的・成人向けの内容',\n violence: '暴力・脅迫',\n other: '不適切な内容',\n },\n },\n moderationStrike: {\n liftSoon: 'まもなく解除',\n liftInHours: '約{hours}時間後に解除',\n liftInDays: '約{days}日後に解除',\n liftInDaysHours: '約{days}日{hours}時間後に解除',\n },\n posts: {\n boardIdRequired: '[memi-board] boardIdが必要です。',\n photoRequired: '写真をアップロードしてください。',\n bodyRequired: '本文にテキストを入力するか、画像を添付してください。',\n titleRequired: 'タイトルを入力してください。',\n },\n profile: {\n notFound: 'ユーザーが見つかりません。',\n noName: '名前なし',\n joined: '登録 {time}',\n lastVisit: '最終訪問 {time}',\n },\n profileEditModal: {\n imageOnly: '画像ファイルのみ選択できます。',\n nameRequired: '名前を入力してください。',\n saveFailed: 'プロフィールを保存できませんでした。',\n title: 'プロフィールを編集',\n changePhoto: '写真を変更',\n name: '名前',\n bio: '自己紹介',\n bioPlaceholder: '自己紹介を書いてみましょう',\n },\n reportButton: {\n failed: '通報できませんでした。',\n reported: '通報済み',\n title: '投稿を通報',\n done: '通報を受け付けました。スタッフが内容を確認します。',\n reason: '理由',\n detailPlaceholder: '詳細(任意)',\n submit: '通報する',\n },\n reportList: {\n staffOnly: '通報一覧はスタッフのみ閲覧できます。',\n loadFailed: '一覧を読み込めませんでした: {error}',\n empty: '対応待ちの通報はありません。',\n untitled: '無題の投稿',\n author: '投稿者 {name}',\n dismiss: '却下',\n confirm: '対応済み',\n },\n reports: {\n reason: {\n spam: 'スパム・広告',\n abuse: '暴言・ヘイト・嫌がらせ',\n adult: 'わいせつな内容',\n illegal: '違法な情報',\n other: 'その他',\n },\n fallbackLabel: '通報',\n signInRequired: 'ログインが必要です。',\n cannotReportOwn: '自分の投稿は通報できません。',\n reasonRequired: '通報理由を選択してください。',\n detailTooLong: '詳細は{max}文字までです。',\n },\n sectionUtil: {\n kind: {\n list: '投稿一覧',\n post: '投稿',\n comments: 'コメントまとめ',\n },\n sort: {\n latest: '新着順',\n likes: 'いいね順',\n },\n untitledPost: '投稿',\n view: {\n media: 'メディア',\n list: 'リスト',\n },\n },\n sections: {\n defaultTitle: 'セクション{n}',\n },\n seo: {\n allCategory: 'すべて',\n boardDescription: '{name}掲示板',\n allDescription: '掲示板 — お知らせやコミュニティの最新情報をチェックしましょう。',\n postFallbackTitle: '投稿 | {site}',\n postFallbackDescription: '掲示板',\n photo: '写真',\n postDescriptionFallback: '掲示板の投稿',\n listTitle: '{name}掲示板 | {site}',\n listTitleAll: '掲示板 | {site}',\n listDescription: '{name}掲示板 — 最新の投稿をチェックしましょう。',\n listDescriptionAll: '掲示板 — お知らせや話題をチェックしましょう。',\n },\n settings: {\n loading: '設定を読み込んでいます。',\n noAccess: 'アクセス権限がありません',\n notFound: {\n title: '存在しない掲示板です',\n checkAddress: 'アドレスをもう一度確認してください。',\n checkBoardAddress: '掲示板のアドレスをもう一度確認してください。',\n },\n newBoard: {\n title: 'まだ存在しない掲示板です',\n description: '下の情報を入力して保存すると、このIDで新しく作成されます。',\n },\n noLabel: 'ラベルなし',\n option: {\n default: '標準',\n },\n id: {\n label: 'カテゴリーID',\n help: 'URLとデータで使われる識別値',\n },\n writeRole: {\n label: '投稿権限',\n help: 'このカテゴリーに投稿できる最低ロール',\n helpShort: '投稿できる最低ロール',\n options: {\n user: '一般ユーザー以上',\n staff: 'スタッフ以上',\n admin: '管理者のみ',\n },\n },\n commentWriteRole: {\n label: 'コメント権限',\n help: 'このカテゴリーにコメントできる最低ロール',\n helpShort: 'コメントできる最低ロール',\n hiddenFixed: '担当スタッフのみ(非表示ボードでは固定)',\n },\n staff: {\n label: '担当スタッフ',\n help: '指定したスタッフだけがこのボードを設定・管理します。空欄の場合は管理者のみ',\n placeholder: '管理者のみ(スタッフ未指定)',\n },\n label: {\n label: '表示名',\n help: 'ユーザーに表示される名前',\n },\n description: {\n label: '説明',\n help: '掲示板の上部などに表示される案内文',\n placeholder: 'この掲示板の短い説明(任意)',\n },\n visibility: {\n label: '公開範囲',\n options: {\n public: {\n label: '表示',\n description: '全体の一覧・フィルターに表示',\n },\n hidden: {\n label: '非表示',\n description: '日記・非公開用。コメントは担当スタッフのみ',\n },\n },\n },\n listView: {\n label: '一覧表示',\n help: '投稿一覧の表示方法',\n options: {\n dense: 'コンパクト',\n video: '動画',\n },\n },\n editorType: {\n label: '入力フォーム',\n help: '投稿画面の作成方法',\n options: {\n default: 'タイトルと本文を入力',\n image: '複数の写真とカバー写真を登録',\n },\n },\n locale: {\n label: '掲示板の言語',\n auto: '自動(サイトの言語に従う)',\n },\n action: {\n moveDown: '下へ',\n goToBoard: '掲示板へ移動',\n deleteBoard: '掲示板を削除',\n create: '作成',\n },\n newCategoryPlaceholder: '新しいカテゴリー名',\n savedCategory: '「{label}」カテゴリーを保存しました。',\n savedSettings: '掲示板の設定を保存しました。',\n created: '掲示板を作成しました。',\n error: {\n orderFailed: 'カテゴリーの順序を保存できませんでした。',\n deleteFailed: '掲示板と関連データを削除できませんでした。',\n saveFailed: '掲示板の設定を保存できませんでした。',\n deleteAllFailed: '掲示板のデータを削除できませんでした。',\n },\n danger: {\n title: '危険な操作',\n confirmLabel: '確認のため「{phrase}」と入力してください',\n phrase: '掲示板のデータを削除',\n button: 'すべてのデータを削除',\n done: '掲示板のデータをすべて削除しました。',\n },\n },\n shareButton: {\n copied: 'リンクをコピーしました',\n },\n signIn: {\n withGoogle: 'Googleでログイン',\n withApple: 'Appleでログイン',\n or: 'または',\n name: '名前',\n email: 'メールアドレス',\n password: 'パスワード',\n signUp: '新規登録',\n toSignUp: 'アカウントをお持ちでないですか?新規登録',\n toSignIn: 'すでにアカウントをお持ちですか?ログイン',\n },\n storage: {\n sourceTooLarge: '元の画像は{max}MB以下にしてください。',\n imageOnly: '画像ファイルのみアップロードできます。',\n canvasUnavailable: 'Canvasを使用できません',\n compressFailed: '圧縮に失敗しました',\n loadFailed: '画像の読み込みに失敗しました',\n },\n swipeHint: {\n title: '左右にスワイプしてみましょう',\n description: '左にスワイプすると次の投稿、右にスワイプすると前の投稿に移動します。',\n },\n userCommentList: {\n loadFailed: '一覧を読み込めませんでした: {error}',\n empty: 'コメントはまだありません。',\n blinded: '管理者により非表示にされたコメントです。',\n likes: 'いいね {count}',\n },\n userPostList: {\n loadFailed: '一覧を読み込めませんでした: {error}',\n empty: '投稿はまだありません。',\n },\n users: {\n changeRoleFailed: 'ロールを変更できませんでした。',\n loading: 'ユーザー一覧を読み込んでいます。',\n noPermission: {\n title: '権限がありません',\n description: '掲示板の管理者のみユーザーのロールを管理できます。',\n },\n empty: '掲示板にログインしたユーザーはいません。',\n noName: '名前なし',\n moderationWarnings: 'コンテンツ警告 {count}回',\n },\n writingAssistant: {\n loginRequired: 'AI文章アシスタントはログイン後に利用できます。',\n userMissing: 'ユーザー情報を確認してから、もう一度お試しください。',\n contentRequired: 'AIで整える内容を先に入力してください。',\n customRequired: 'どのように書き換えるか指示を入力してください。',\n emptyResult: 'AIが結果を生成できませんでした。もう一度お試しください。',\n failed: 'AI処理に失敗しました。もう一度お試しください。',\n actions: {\n proofread: 'スペルチェック',\n polish: '文章を整える',\n continue: '自然に続きを書く',\n summarize: '短く要約',\n translateEn: '英語に翻訳',\n translateKo: '韓国語に翻訳',\n title: '本文からタイトルを生成',\n custom: 'カスタムスタイルに書き換え…',\n },\n },\n}\n\nexport default messages\n"],"mappings":"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"}
package/dist/module.mjs CHANGED
@@ -33,53 +33,46 @@ var s = a({
33
33
  let p = new Set(s.options.vite.optimizeDeps.exclude || []);
34
34
  p.add("memi-board"), s.options.vite.optimizeDeps.exclude = [...p], s.options.imports ||= {}, s.options.imports.transform ||= {};
35
35
  let m = /* @__PURE__ */ new Set([...s.options.imports.transform.exclude || [], /[\\/]memi-board[\\/]dist[\\/]/]);
36
- s.options.imports.transform.exclude = [...m];
37
- let h = /* @__PURE__ */ new Set([
38
- ...s.options.vite.optimizeDeps.include || [],
39
- "dayjs",
40
- "dayjs/plugin/relativeTime",
41
- "dayjs/locale/ko"
42
- ]);
43
- s.options.vite.optimizeDeps.include = [...h], e({
36
+ s.options.imports.transform.exclude = [...m], e({
44
37
  path: l,
45
38
  pathPrefix: !1,
46
39
  prefix: "MemiBoard"
47
40
  });
48
- let g = [
41
+ let h = [
49
42
  c("../src/composables/useMemiBoardSeo.ts"),
50
43
  c("./runtime/composables/useMemiBoardSeo.ts"),
51
44
  c("./composables/useMemiBoardSeo.ts")
52
45
  ].find((e) => o(e));
53
- if (!g) throw Error("[memi-board] useMemiBoardSeo runtime not found");
54
- let _ = "memi-board/runtime";
46
+ if (!h) throw Error("[memi-board] useMemiBoardSeo runtime not found");
47
+ let g = "memi-board/runtime";
55
48
  t([
56
49
  {
57
50
  name: "configureMemiBoard",
58
- from: _
51
+ from: g
59
52
  },
60
53
  {
61
54
  name: "useMemiBoardConfig",
62
- from: _
55
+ from: g
63
56
  },
64
57
  {
65
58
  name: "useMemiBoardAuth",
66
- from: _
59
+ from: g
67
60
  },
68
61
  {
69
62
  name: "useMemiBoardPosts",
70
- from: _
63
+ from: g
71
64
  },
72
65
  {
73
66
  name: "useMemiBoardComments",
74
- from: _
67
+ from: g
75
68
  },
76
69
  {
77
70
  name: "useMemiBoardViews",
78
- from: _
71
+ from: g
79
72
  },
80
73
  {
81
74
  name: "useMemiBoardModeration",
82
- from: _
75
+ from: g
83
76
  },
84
77
  {
85
78
  name: "useMemiBoardStorage",
@@ -87,48 +80,79 @@ var s = a({
87
80
  },
88
81
  {
89
82
  name: "useMemiBoardSettings",
90
- from: _
83
+ from: g
91
84
  },
92
85
  {
93
86
  name: "useMemiBoardUsers",
94
- from: _
87
+ from: g
95
88
  },
96
89
  {
97
90
  name: "useMemiBoardPostSeo",
98
- from: g
91
+ from: h
99
92
  },
100
93
  {
101
94
  name: "useMemiBoardListSeo",
102
- from: g
95
+ from: h
103
96
  },
104
97
  {
105
98
  name: "fetchPublicPostForSeo",
106
- from: _
99
+ from: g
107
100
  },
108
101
  {
109
102
  name: "fetchPublicListForSeo",
110
- from: _
103
+ from: g
111
104
  },
112
105
  {
113
106
  name: "resolvePublicSeoDb",
114
- from: _
107
+ from: g
115
108
  },
116
109
  {
117
110
  name: "versionHistory",
118
- from: _
111
+ from: g
112
+ },
113
+ {
114
+ name: "useMemiBoardI18n",
115
+ from: g
116
+ },
117
+ {
118
+ name: "MEMI_BOARD_LOCALES",
119
+ from: g
120
+ },
121
+ {
122
+ name: "useMemiBoardAutoTranslate",
123
+ from: g
119
124
  }
120
125
  ]);
121
- let v = JSON.stringify(a).replace(/</g, "\\u003c"), y = r({
126
+ let _ = JSON.stringify(a).replace(/</g, "\\u003c"), v = r({
122
127
  filename: "memi-board.config.mjs",
123
128
  getContents: () => `
124
- import { configureMemiBoard } from 'memi-board/runtime'
129
+ import { computed } from 'vue'
130
+ import {
131
+ configureMemiBoard,
132
+ loadMemiBoardLocale,
133
+ memiBoardHostLocaleKey,
134
+ normalizeMemiBoardLocale,
135
+ } from 'memi-board/runtime'
125
136
 
126
- export default defineNuxtPlugin(() => {
127
- configureMemiBoard(${v})
137
+ export default defineNuxtPlugin({
138
+ name: 'memi-board:config',
139
+ // @nuxtjs/i18n 플러그인이 $i18n 을 만든 뒤 실행되어야 한다.
140
+ dependsOn: ['i18n:plugin'],
141
+ async setup(nuxtApp) {
142
+ configureMemiBoard(${_})
143
+ // 호스트가 @nuxtjs/i18n 을 쓰면 그 언어를 게시판 기본 언어로 쓴다.
144
+ // 요청(SSR)마다 앱 인스턴스가 따로라 provide 로 넘긴다.
145
+ const i18n = nuxtApp.$i18n
146
+ if (!i18n?.locale) return
147
+ const hostLocale = computed(() => i18n.locale.value)
148
+ nuxtApp.vueApp.provide(memiBoardHostLocaleKey, hostLocale)
149
+ const initial = normalizeMemiBoardLocale(hostLocale.value)
150
+ if (initial) await loadMemiBoardLocale(initial)
151
+ },
128
152
  })
129
153
  `
130
154
  });
131
- n(y.dst);
155
+ n(v.dst);
132
156
  }
133
157
  });
134
158
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"module.mjs","names":[],"sources":["../src/module.ts"],"sourcesContent":["// @ts-nocheck — NuxtModule 반환 타입이 @nuxt/schema 경로에 묶여 d.ts 생성 시 불안정\nimport {\n defineNuxtModule,\n createResolver,\n addComponentsDir,\n addImports,\n addPlugin,\n addTemplate,\n} from '@nuxt/kit'\nimport { existsSync } from 'node:fs'\nimport type { NuxtModule } from '@nuxt/schema'\nimport type { MemiBoardConfig } from './config'\n\ntype MemiBoardModuleOptions = Partial<MemiBoardConfig>\n\n/**\n * Nuxt 전용 모듈 — 호스트 Vite 파이프라인에 게시판 SFC와 필수 설정을 올린다.\n *\n * 하지 않는 일:\n * - nuxt-vuefire / Firebase 설정\n * - 라우트·미들웨어 등록\n *\n * 하는 일:\n * - components 디렉터리 등록 → 호스트가 SFC 컴파일 → Nuxt UI auto-import 정상 동작\n * - composable / configure 를 auto-import\n * - memiBoard 옵션을 런타임 플러그인으로 전달해 configureMemiBoard 자동 호출\n * - transpile + optimizeDeps 설정으로 linked package와 CommonJS 의존성 정규화\n */\nconst memiBoardModule: NuxtModule<MemiBoardModuleOptions> = defineNuxtModule<MemiBoardModuleOptions>({\n meta: {\n name: 'memi-board',\n configKey: 'memiBoard',\n },\n setup(options, nuxt) {\n const { resolve } = createResolver(import.meta.url)\n\n // 우선순위:\n // 1) monorepo link 시 dist/module.mjs → ../src/components (소스 직접, 재빌드 없이 UI 수정)\n // 2) publish 패키지 dist/runtime/components\n // 3) src/module.ts 로 직접 로드할 때 ./components\n const candidates = [\n resolve('../src/components'),\n resolve('./runtime/components'),\n resolve('./components'),\n ]\n const componentsDir = candidates.find(p => existsSync(p))\n if (!componentsDir) {\n throw new Error('[memi-board] components directory not found')\n }\n nuxt.options.build.transpile.push('memi-board')\n\n nuxt.options.vite ||= {}\n\n // link:/file: 설치 시 memi-board 패키지 루트(dist/ 등)가 호스트의 node_modules\n // 밖에 있어서 Vite dev 서버의 fs.allow 기본값(root + node_modules)에 안 걸린다 —\n // /@fs/ 요청이 403(\"outside of Vite serving allow list\")으로 막히고, 그 403 HTML을\n // JS로 파싱하려다 알 수 없는 SyntaxError가 난다. 패키지 루트를 명시적으로 허용한다.\n const packageRoot = resolve('..')\n nuxt.options.vite.server ||= {}\n nuxt.options.vite.server.fs ||= {}\n const fsAllow = new Set([\n ...(nuxt.options.vite.server.fs.allow || []),\n packageRoot,\n ])\n nuxt.options.vite.server.fs.allow = [...fsAllow]\n\n nuxt.options.vite.resolve ||= {}\n // link:/file: 로 설치 시 패키지 쪽 node_modules 의 vuefire·firebase 가\n // 호스트와 이중으로 잡히면 useFirestore 가 깨져 permission-denied 가 난다.\n const dedupe = new Set([\n ...(nuxt.options.vite.resolve.dedupe || []),\n 'vue',\n 'vue-router',\n 'vuefire',\n 'firebase',\n 'nuxt',\n '@tiptap/core',\n '@tiptap/pm',\n '@tiptap/vue-3',\n ])\n nuxt.options.vite.resolve.dedupe = [...dedupe]\n\n nuxt.options.vite.optimizeDeps ||= {}\n const exclude = new Set(nuxt.options.vite.optimizeDeps.exclude || [])\n exclude.add('memi-board')\n nuxt.options.vite.optimizeDeps.exclude = [...exclude]\n\n // link:/file: 개발 중엔 memi-board의 실제 경로가 host의 node_modules 밖에 있어서\n // Nuxt auto-import(unimport)의 \"node_modules는 건드리지 않는다\" 체크(경로에\n // 'node_modules' 문자열이 있는지로 판단)를 그냥 통과해버린다 — 그러면 memi-board의\n // dist 청크를 \"프로젝트 소스\"로 스캔하다가, rollup이 공유 청크의 export를 붙일 때\n // 우연히 짧은 별칭(a, b, … h …)을 골랐는데 그게 Vue의 전역 auto-import `h`\n // (hyperscript)와 겹치면 `import { h } from 'vue'`를 그 청크에 주입해버려서\n // 이미 있는 `h` export 별칭과 충돌한다(\"Identifier 'h' has already been declared\").\n // 명시적으로 제외해 이 청크는 절대 auto-import 스캔 대상이 되지 않게 한다\n // (published npm 패키지 설치 시엔 이미 node_modules 안이라 원래도 제외 대상).\n nuxt.options.imports ||= {}\n nuxt.options.imports.transform ||= {}\n const transformExclude = new Set([\n ...(nuxt.options.imports.transform.exclude || []),\n /[\\\\/]memi-board[\\\\/]dist[\\\\/]/,\n ])\n nuxt.options.imports.transform.exclude = [...transformExclude]\n\n // CommentItem 이 사용하는 dayjs(CommonJS)를 개발 서버에서도 ESM 형태로\n // 사전 번들링한다. 호스트가 같은 설정을 별도로 작성할 필요가 없다.\n const include = new Set([\n ...(nuxt.options.vite.optimizeDeps.include || []),\n 'dayjs',\n 'dayjs/plugin/relativeTime',\n 'dayjs/locale/ko',\n ])\n nuxt.options.vite.optimizeDeps.include = [...include]\n\n addComponentsDir({\n path: componentsDir,\n pathPrefix: false,\n prefix: 'MemiBoard',\n // List.vue → MemiBoardList\n })\n\n // SEO: 호스트 Nuxt 가 소스를 컴파일해야 #imports / useSeoMeta 가 앱 인스턴스를 탄다.\n // dist/index.js 에 넣으면 link 시 패키지 node_modules/nuxt 로 해석되어 깨진다.\n const seoCandidates = [\n resolve('../src/composables/useMemiBoardSeo.ts'),\n resolve('./runtime/composables/useMemiBoardSeo.ts'),\n resolve('./composables/useMemiBoardSeo.ts'),\n ]\n const seoFrom = seoCandidates.find(p => existsSync(p))\n if (!seoFrom) {\n throw new Error('[memi-board] useMemiBoardSeo runtime not found')\n }\n\n const from = 'memi-board/runtime'\n addImports([\n { name: 'configureMemiBoard', from },\n { name: 'useMemiBoardConfig', from },\n { name: 'useMemiBoardAuth', from },\n { name: 'useMemiBoardPosts', from },\n { name: 'useMemiBoardComments', from },\n { name: 'useMemiBoardViews', from },\n { name: 'useMemiBoardModeration', from },\n // 이미지 압축 등 브라우저 전용 — SSR 서버 번들에 안 섞이도록 별도 서브패스에서 해석\n { name: 'useMemiBoardStorage', from: 'memi-board/storage' },\n { name: 'useMemiBoardSettings', from },\n { name: 'useMemiBoardUsers', from },\n { name: 'useMemiBoardPostSeo', from: seoFrom },\n { name: 'useMemiBoardListSeo', from: seoFrom },\n { name: 'fetchPublicPostForSeo', from },\n { name: 'fetchPublicListForSeo', from },\n { name: 'resolvePublicSeoDb', from },\n { name: 'versionHistory', from },\n ])\n\n const runtimeConfig = JSON.stringify(options).replace(/</g, '\\\\u003c')\n const configPlugin = addTemplate({\n filename: 'memi-board.config.mjs',\n getContents: () => `\nimport { configureMemiBoard } from 'memi-board/runtime'\n\nexport default defineNuxtPlugin(() => {\n configureMemiBoard(${runtimeConfig})\n})\n`,\n })\n addPlugin(configPlugin.dst)\n },\n})\n\nexport default memiBoardModule\n"],"mappings":"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"}
1
+ {"version":3,"file":"module.mjs","names":[],"sources":["../src/module.ts"],"sourcesContent":["// @ts-nocheck — NuxtModule 반환 타입이 @nuxt/schema 경로에 묶여 d.ts 생성 시 불안정\nimport {\n defineNuxtModule,\n createResolver,\n addComponentsDir,\n addImports,\n addPlugin,\n addTemplate,\n} from '@nuxt/kit'\nimport { existsSync } from 'node:fs'\nimport type { NuxtModule } from '@nuxt/schema'\nimport type { MemiBoardConfig } from './config'\n\ntype MemiBoardModuleOptions = Partial<MemiBoardConfig>\n\n/**\n * Nuxt 전용 모듈 — 호스트 Vite 파이프라인에 게시판 SFC와 필수 설정을 올린다.\n *\n * 하지 않는 일:\n * - nuxt-vuefire / Firebase 설정\n * - 라우트·미들웨어 등록\n *\n * 하는 일:\n * - components 디렉터리 등록 → 호스트가 SFC 컴파일 → Nuxt UI auto-import 정상 동작\n * - composable / configure 를 auto-import\n * - memiBoard 옵션을 런타임 플러그인으로 전달해 configureMemiBoard 자동 호출\n * - transpile + optimizeDeps 설정으로 linked package와 CommonJS 의존성 정규화\n */\nconst memiBoardModule: NuxtModule<MemiBoardModuleOptions> = defineNuxtModule<MemiBoardModuleOptions>({\n meta: {\n name: 'memi-board',\n configKey: 'memiBoard',\n },\n setup(options, nuxt) {\n const { resolve } = createResolver(import.meta.url)\n\n // 우선순위:\n // 1) monorepo link 시 dist/module.mjs → ../src/components (소스 직접, 재빌드 없이 UI 수정)\n // 2) publish 패키지 dist/runtime/components\n // 3) src/module.ts 로 직접 로드할 때 ./components\n const candidates = [\n resolve('../src/components'),\n resolve('./runtime/components'),\n resolve('./components'),\n ]\n const componentsDir = candidates.find(p => existsSync(p))\n if (!componentsDir) {\n throw new Error('[memi-board] components directory not found')\n }\n nuxt.options.build.transpile.push('memi-board')\n\n nuxt.options.vite ||= {}\n\n // link:/file: 설치 시 memi-board 패키지 루트(dist/ 등)가 호스트의 node_modules\n // 밖에 있어서 Vite dev 서버의 fs.allow 기본값(root + node_modules)에 안 걸린다 —\n // /@fs/ 요청이 403(\"outside of Vite serving allow list\")으로 막히고, 그 403 HTML을\n // JS로 파싱하려다 알 수 없는 SyntaxError가 난다. 패키지 루트를 명시적으로 허용한다.\n const packageRoot = resolve('..')\n nuxt.options.vite.server ||= {}\n nuxt.options.vite.server.fs ||= {}\n const fsAllow = new Set([\n ...(nuxt.options.vite.server.fs.allow || []),\n packageRoot,\n ])\n nuxt.options.vite.server.fs.allow = [...fsAllow]\n\n nuxt.options.vite.resolve ||= {}\n // link:/file: 로 설치 시 패키지 쪽 node_modules 의 vuefire·firebase 가\n // 호스트와 이중으로 잡히면 useFirestore 가 깨져 permission-denied 가 난다.\n const dedupe = new Set([\n ...(nuxt.options.vite.resolve.dedupe || []),\n 'vue',\n 'vue-router',\n 'vuefire',\n 'firebase',\n 'nuxt',\n '@tiptap/core',\n '@tiptap/pm',\n '@tiptap/vue-3',\n ])\n nuxt.options.vite.resolve.dedupe = [...dedupe]\n\n nuxt.options.vite.optimizeDeps ||= {}\n const exclude = new Set(nuxt.options.vite.optimizeDeps.exclude || [])\n exclude.add('memi-board')\n nuxt.options.vite.optimizeDeps.exclude = [...exclude]\n\n // link:/file: 개발 중엔 memi-board의 실제 경로가 host의 node_modules 밖에 있어서\n // Nuxt auto-import(unimport)의 \"node_modules는 건드리지 않는다\" 체크(경로에\n // 'node_modules' 문자열이 있는지로 판단)를 그냥 통과해버린다 — 그러면 memi-board의\n // dist 청크를 \"프로젝트 소스\"로 스캔하다가, rollup이 공유 청크의 export를 붙일 때\n // 우연히 짧은 별칭(a, b, … h …)을 골랐는데 그게 Vue의 전역 auto-import `h`\n // (hyperscript)와 겹치면 `import { h } from 'vue'`를 그 청크에 주입해버려서\n // 이미 있는 `h` export 별칭과 충돌한다(\"Identifier 'h' has already been declared\").\n // 명시적으로 제외해 이 청크는 절대 auto-import 스캔 대상이 되지 않게 한다\n // (published npm 패키지 설치 시엔 이미 node_modules 안이라 원래도 제외 대상).\n nuxt.options.imports ||= {}\n nuxt.options.imports.transform ||= {}\n const transformExclude = new Set([\n ...(nuxt.options.imports.transform.exclude || []),\n /[\\\\/]memi-board[\\\\/]dist[\\\\/]/,\n ])\n nuxt.options.imports.transform.exclude = [...transformExclude]\n\n addComponentsDir({\n path: componentsDir,\n pathPrefix: false,\n prefix: 'MemiBoard',\n // List.vue → MemiBoardList\n })\n\n // SEO: 호스트 Nuxt 가 소스를 컴파일해야 #imports / useSeoMeta 가 앱 인스턴스를 탄다.\n // dist/index.js 에 넣으면 link 시 패키지 node_modules/nuxt 로 해석되어 깨진다.\n const seoCandidates = [\n resolve('../src/composables/useMemiBoardSeo.ts'),\n resolve('./runtime/composables/useMemiBoardSeo.ts'),\n resolve('./composables/useMemiBoardSeo.ts'),\n ]\n const seoFrom = seoCandidates.find(p => existsSync(p))\n if (!seoFrom) {\n throw new Error('[memi-board] useMemiBoardSeo runtime not found')\n }\n\n const from = 'memi-board/runtime'\n addImports([\n { name: 'configureMemiBoard', from },\n { name: 'useMemiBoardConfig', from },\n { name: 'useMemiBoardAuth', from },\n { name: 'useMemiBoardPosts', from },\n { name: 'useMemiBoardComments', from },\n { name: 'useMemiBoardViews', from },\n { name: 'useMemiBoardModeration', from },\n // 이미지 압축 등 브라우저 전용 — SSR 서버 번들에 안 섞이도록 별도 서브패스에서 해석\n { name: 'useMemiBoardStorage', from: 'memi-board/storage' },\n { name: 'useMemiBoardSettings', from },\n { name: 'useMemiBoardUsers', from },\n { name: 'useMemiBoardPostSeo', from: seoFrom },\n { name: 'useMemiBoardListSeo', from: seoFrom },\n { name: 'fetchPublicPostForSeo', from },\n { name: 'fetchPublicListForSeo', from },\n { name: 'resolvePublicSeoDb', from },\n { name: 'versionHistory', from },\n { name: 'useMemiBoardI18n', from },\n { name: 'MEMI_BOARD_LOCALES', from },\n { name: 'useMemiBoardAutoTranslate', from },\n ])\n\n const runtimeConfig = JSON.stringify(options).replace(/</g, '\\\\u003c')\n const configPlugin = addTemplate({\n filename: 'memi-board.config.mjs',\n getContents: () => `\nimport { computed } from 'vue'\nimport {\n configureMemiBoard,\n loadMemiBoardLocale,\n memiBoardHostLocaleKey,\n normalizeMemiBoardLocale,\n} from 'memi-board/runtime'\n\nexport default defineNuxtPlugin({\n name: 'memi-board:config',\n // @nuxtjs/i18n 플러그인이 $i18n 을 만든 뒤 실행되어야 한다.\n dependsOn: ['i18n:plugin'],\n async setup(nuxtApp) {\n configureMemiBoard(${runtimeConfig})\n // 호스트가 @nuxtjs/i18n 을 쓰면 그 언어를 게시판 기본 언어로 쓴다.\n // 요청(SSR)마다 앱 인스턴스가 따로라 provide 로 넘긴다.\n const i18n = nuxtApp.$i18n\n if (!i18n?.locale) return\n const hostLocale = computed(() => i18n.locale.value)\n nuxtApp.vueApp.provide(memiBoardHostLocaleKey, hostLocale)\n const initial = normalizeMemiBoardLocale(hostLocale.value)\n if (initial) await loadMemiBoardLocale(initial)\n },\n})\n`,\n })\n addPlugin(configPlugin.dst)\n },\n})\n\nexport default memiBoardModule\n"],"mappings":"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"}