memi-board 0.46.0 → 0.46.2

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 (53) hide show
  1. package/README.md +1 -0
  2. package/dist/{ar-BCQdRw_S.js → ar-D_6hknjh.js} +22 -1
  3. package/dist/ar-D_6hknjh.js.map +1 -0
  4. package/dist/composables/fetchPublicSeo.d.ts +1 -1
  5. package/dist/composables/useMemiBoardAutoTranslate.d.ts +6 -6
  6. package/dist/composables/useMemiBoardPosts.d.ts +6 -1
  7. package/dist/composables/useMemiBoardSettings.d.ts +5 -4
  8. package/dist/composables/useMemiBoardWritingAssistant.d.ts +8 -0
  9. package/dist/{de-ddWQNaqs.js → de-DQqSsBsZ.js} +22 -1
  10. package/dist/de-DQqSsBsZ.js.map +1 -0
  11. package/dist/{en-CaPfPNDy.js → en-Broh-9df.js} +19 -1
  12. package/dist/en-Broh-9df.js.map +1 -0
  13. package/dist/{es-7JHjGVlM.js → es-D3eEYN6w.js} +22 -1
  14. package/dist/es-D3eEYN6w.js.map +1 -0
  15. package/dist/{fr-C3NCMNoy.js → fr-CbXPRKeU.js} +22 -1
  16. package/dist/fr-CbXPRKeU.js.map +1 -0
  17. package/dist/{id-C8hCAMPJ.js → id-DxVqvPpo.js} +22 -1
  18. package/dist/id-DxVqvPpo.js.map +1 -0
  19. package/dist/index.d.ts +3 -2
  20. package/dist/index.js +1266 -921
  21. package/dist/index.js.map +1 -1
  22. package/dist/{ja-oTWri4hY.js → ja-D2dIWUse.js} +22 -1
  23. package/dist/{ja-oTWri4hY.js.map → ja-D2dIWUse.js.map} +1 -1
  24. package/dist/{pt-B9EH4scA.js → pt-BAuHdglU.js} +22 -1
  25. package/dist/pt-BAuHdglU.js.map +1 -0
  26. package/dist/runtime/components/CategorySettings.vue +80 -14
  27. package/dist/runtime/components/Detail.vue +9 -7
  28. package/dist/runtime/components/Editor.vue +79 -8
  29. package/dist/runtime/components/List.vue +2 -2
  30. package/dist/runtime/components/ListDefault.vue +16 -6
  31. package/dist/runtime/components/ListDense.vue +8 -4
  32. package/dist/runtime/components/ListImage.vue +13 -6
  33. package/dist/runtime/components/ListVideo.vue +14 -5
  34. package/dist/runtime/components/Section.vue +10 -3
  35. package/dist/runtime/components/Settings.vue +77 -11
  36. package/dist/runtime/composables/useMemiBoardSeo.ts +3 -3
  37. package/dist/{slugify-DJ82ifCd.js → slugify-B05Qykf_.js} +28 -10
  38. package/dist/slugify-B05Qykf_.js.map +1 -0
  39. package/dist/storage.js +1 -1
  40. package/dist/types.d.ts +48 -0
  41. package/dist/utils/localizedFields.d.ts +33 -0
  42. package/dist/{zh-D5rDYV6E.js → zh-CMyzTdQ5.js} +22 -1
  43. package/dist/zh-CMyzTdQ5.js.map +1 -0
  44. package/package.json +1 -1
  45. package/dist/ar-BCQdRw_S.js.map +0 -1
  46. package/dist/de-ddWQNaqs.js.map +0 -1
  47. package/dist/en-CaPfPNDy.js.map +0 -1
  48. package/dist/es-7JHjGVlM.js.map +0 -1
  49. package/dist/fr-C3NCMNoy.js.map +0 -1
  50. package/dist/id-C8hCAMPJ.js.map +0 -1
  51. package/dist/pt-B9EH4scA.js.map +0 -1
  52. package/dist/slugify-DJ82ifCd.js.map +0 -1
  53. package/dist/zh-D5rDYV6E.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slugify-B05Qykf_.js","names":[],"sources":["../src/utils/boardPaths.ts","../src/config.ts","../src/i18n/locales.ts","../src/i18n/messages/ko/attachments.ts","../src/i18n/messages/ko/auth.ts","../src/i18n/messages/ko/authorMemo.ts","../src/i18n/messages/ko/authorMenu.ts","../src/i18n/messages/ko/avatarCropModal.ts","../src/i18n/messages/ko/boardSettings.ts","../src/i18n/messages/ko/boardUsers.ts","../src/i18n/messages/ko/commentFeed.ts","../src/i18n/messages/ko/commentForm.ts","../src/i18n/messages/ko/commentItem.ts","../src/i18n/messages/ko/commentList.ts","../src/i18n/messages/ko/commentThread.ts","../src/i18n/messages/ko/comments.ts","../src/i18n/messages/ko/common.ts","../src/i18n/messages/ko/detail.ts","../src/i18n/messages/ko/editor.ts","../src/i18n/messages/ko/footer.ts","../src/i18n/messages/ko/likes.ts","../src/i18n/messages/ko/list.ts","../src/i18n/messages/ko/listViewSwitch.ts","../src/i18n/messages/ko/miniComments.ts","../src/i18n/messages/ko/miniList.ts","../src/i18n/messages/ko/miniPicker.ts","../src/i18n/messages/ko/miniPost.ts","../src/i18n/messages/ko/moderation.ts","../src/i18n/messages/ko/moderationPrompt.ts","../src/i18n/messages/ko/moderationStrike.ts","../src/i18n/messages/ko/posts.ts","../src/i18n/messages/ko/profile.ts","../src/i18n/messages/ko/profileEditModal.ts","../src/i18n/messages/ko/reportButton.ts","../src/i18n/messages/ko/reportList.ts","../src/i18n/messages/ko/reports.ts","../src/i18n/messages/ko/sectionUtil.ts","../src/i18n/messages/ko/sections.ts","../src/i18n/messages/ko/seo.ts","../src/i18n/messages/ko/settings.ts","../src/i18n/messages/ko/shareButton.ts","../src/i18n/messages/ko/signIn.ts","../src/i18n/messages/ko/storage.ts","../src/i18n/messages/ko/swipeHint.ts","../src/i18n/messages/ko/userCommentList.ts","../src/i18n/messages/ko/userPostList.ts","../src/i18n/messages/ko/users.ts","../src/i18n/messages/ko/writingAssistant.ts","../src/i18n/messages/ko/index.ts","../src/i18n/translate.ts","../src/utils/formatDate.ts","../src/i18n/useMemiBoardI18n.ts","../src/utils/slugify.ts"],"sourcesContent":["/**\n * Firestore / Storage 경로\n *\n * ```\n * memiBoardUsers/{uid}\n * memiBoardSettings/{boardId} // 보드 설정 (구 memiBoards/{id} stub + settings/config 통합)\n * memiBoardPosts/{postId} // boardId 는 문서 필드\n * memiBoardPosts/{postId}/body/main\n * memiBoardComments/{commentId} // postId, boardId 는 문서 필드\n * memiBoardLikes/{targetId}_{uid} // 글: postId_uid / 댓글: commentId_uid\n * memiBoardReports/{postId}_{uid} // 글 신고. 유저당 글당 1건\n * ```\n *\n * Storage: `memiBoardPosts/{postId}/...` (postId 가 전역 고유이므로 boardId 불필요)\n *\n * 카테고리 개념 없음 — 예전 category id 가 곧 boardId. boardId/postId 는 경로가\n * 아니라 문서 필드이므로, 보드/글 단위로 좁혀야 하는 쿼리는 항상 where 필터로\n * 스코핑한다 (컬렉션 자체는 항상 최상위 flat 컬렉션).\n */\nimport {\n collection,\n doc,\n type CollectionReference,\n type DocumentReference,\n type Firestore,\n} from 'firebase/firestore'\n\nexport const DEFAULT_POSTS_COLLECTION = 'memiBoardPosts'\nexport const DEFAULT_COMMENTS_COLLECTION = 'memiBoardComments'\nexport const DEFAULT_LIKES_COLLECTION = 'memiBoardLikes'\nexport const DEFAULT_REPORTS_COLLECTION = 'memiBoardReports'\nexport const DEFAULT_SETTINGS_COLLECTION = 'memiBoardSettings'\nexport const DEFAULT_USERS_COLLECTION = 'memiBoardUsers'\n\nexport interface BoardPathConfig {\n postsCollection: string\n commentsCollection: string\n likesCollection: string\n reportsCollection: string\n settingsCollection: string\n usersCollection: string\n}\n\nexport function resolveBoardPathConfig(input: {\n postsCollection?: string\n commentsCollection?: string\n likesCollection?: string\n reportsCollection?: string\n settingsCollection?: string\n usersCollection?: string\n}): BoardPathConfig {\n return {\n postsCollection: input.postsCollection?.trim() || DEFAULT_POSTS_COLLECTION,\n commentsCollection: input.commentsCollection?.trim() || DEFAULT_COMMENTS_COLLECTION,\n likesCollection: input.likesCollection?.trim() || DEFAULT_LIKES_COLLECTION,\n reportsCollection: input.reportsCollection?.trim() || DEFAULT_REPORTS_COLLECTION,\n settingsCollection: input.settingsCollection?.trim() || DEFAULT_SETTINGS_COLLECTION,\n usersCollection: input.usersCollection?.trim() || DEFAULT_USERS_COLLECTION,\n }\n}\n\n/** 보드 설정 목록/문서 — 구 memiBoards/{boardId} stub + settings/config 통합 */\nexport function settingsCol(db: Firestore, cfg: BoardPathConfig): CollectionReference {\n return collection(db, cfg.settingsCollection)\n}\n\nexport function settingsDoc(\n db: Firestore,\n cfg: BoardPathConfig,\n boardId: string,\n): DocumentReference {\n return doc(db, cfg.settingsCollection, boardId)\n}\n\nexport function postsCol(db: Firestore, cfg: BoardPathConfig): CollectionReference {\n return collection(db, cfg.postsCollection)\n}\n\nexport function postDoc(db: Firestore, cfg: BoardPathConfig, postId: string): DocumentReference {\n return doc(db, cfg.postsCollection, postId)\n}\n\nexport function postBodyDoc(\n db: Firestore,\n cfg: BoardPathConfig,\n postId: string,\n): DocumentReference {\n return doc(db, cfg.postsCollection, postId, 'body', 'main')\n}\n\nexport function commentsCol(db: Firestore, cfg: BoardPathConfig): CollectionReference {\n return collection(db, cfg.commentsCollection)\n}\n\nexport function commentDoc(\n db: Firestore,\n cfg: BoardPathConfig,\n commentId: string,\n): DocumentReference {\n return doc(db, cfg.commentsCollection, commentId)\n}\n\nexport function likesCol(db: Firestore, cfg: BoardPathConfig): CollectionReference {\n return collection(db, cfg.likesCollection)\n}\n\n/** 좋아요 문서ID 관례: `${targetId}_{uid}` — targetId 는 postId 또는 commentId. 토글은 create-or-delete */\nexport function likeDocId(targetId: string, uid: string): string {\n return `${targetId}_${uid}`\n}\n\nexport function likeDoc(\n db: Firestore,\n cfg: BoardPathConfig,\n targetId: string,\n uid: string,\n): DocumentReference {\n return doc(db, cfg.likesCollection, likeDocId(targetId, uid))\n}\n\nexport function reportsCol(db: Firestore, cfg: BoardPathConfig): CollectionReference {\n return collection(db, cfg.reportsCollection)\n}\n\n/** 신고 문서ID: `${postId}_{uid}` — 유저당 글당 1건 */\nexport function reportDocId(postId: string, uid: string): string {\n return `${postId}_${uid}`\n}\n\nexport function reportDoc(\n db: Firestore,\n cfg: BoardPathConfig,\n postId: string,\n uid: string,\n): DocumentReference {\n return doc(db, cfg.reportsCollection, reportDocId(postId, uid))\n}\n\nexport function boardUsersCol(db: Firestore, cfg: BoardPathConfig): CollectionReference {\n return collection(db, cfg.usersCollection)\n}\n\nexport function boardUserDoc(\n db: Firestore,\n cfg: BoardPathConfig,\n uid: string,\n): DocumentReference {\n return doc(db, cfg.usersCollection, uid)\n}\n\n/** 이메일만 담는 비공개 문서 — memiBoardUsers/{uid}는 공개 프로필이라 이메일만 분리한다. */\nexport function boardUserPrivateDoc(\n db: Firestore,\n cfg: BoardPathConfig,\n uid: string,\n): DocumentReference {\n return doc(db, cfg.usersCollection, uid, 'private', 'info')\n}\n\n/** 본인만 보는 작성자 메모 — 문서 ID 자체가 targetUid라 대상당 메모가 하나로 고정된다. */\nexport function authorMemoDoc(\n db: Firestore,\n cfg: BoardPathConfig,\n viewerUid: string,\n targetUid: string,\n): DocumentReference {\n return doc(db, cfg.usersCollection, viewerUid, 'memos', targetUid)\n}\n\n/** postId 가 전역 고유이므로 boardId 프리픽스 불필요 */\nexport function postStorageFolder(cfg: BoardPathConfig, postId: string): string {\n return `${cfg.postsCollection}/${postId}`\n}\n\nexport function boardSsrKey(cfg: BoardPathConfig, suffix: string): string {\n return `${cfg.postsCollection}/${cfg.usersCollection}/${suffix}`\n}\n","import { reactive } from 'vue'\nimport type { BoardUserRole } from './types'\nimport {\n DEFAULT_COMMENTS_COLLECTION,\n DEFAULT_LIKES_COLLECTION,\n DEFAULT_REPORTS_COLLECTION,\n DEFAULT_POSTS_COLLECTION,\n DEFAULT_SETTINGS_COLLECTION,\n DEFAULT_USERS_COLLECTION,\n resolveBoardPathConfig,\n type BoardPathConfig,\n} from './utils/boardPaths'\n\nexport interface MemiBoardAuthOptions {\n providers?: Array<'google' | 'apple' | 'emailPassword'>\n}\n\nexport interface MemiBoardModerationOptions {\n enabled?: boolean\n model?: string\n localBlocklist?: string[]\n onError?: 'allow' | 'block'\n moderateImages?: boolean\n useLimitedUseAppCheckTokens?: boolean\n blockBanThreshold?: number\n blockBanDecayMs?: number\n}\n\nexport interface MemiBoardSeoOptions {\n enabled?: boolean\n siteName?: string\n siteUrl?: string\n defaultOgImage?: string\n /**\n * 호스트 게시판 base path (trailing slash 없음). 기본 '/board'\n * canonical: {base}, {base}/{boardId}, {base}/{boardId}/{slug}\n */\n basePath?: string\n}\n\nexport interface MemiBoardConfig {\n /** 글 컬렉션. 기본 `memiBoardPosts` */\n postsCollection: string\n /** 댓글 컬렉션. 기본 `memiBoardComments` */\n commentsCollection: string\n /** 좋아요 컬렉션. 기본 `memiBoardLikes` */\n likesCollection: string\n /** 신고 컬렉션. 기본 `memiBoardReports` */\n reportsCollection: string\n /** 보드 설정 컬렉션. 기본 `memiBoardSettings` */\n settingsCollection: string\n /** 역할 문서 컬렉션. 기본 `memiBoardUsers` */\n usersCollection: string\n auth: MemiBoardAuthOptions\n moderation: MemiBoardModerationOptions\n seo: MemiBoardSeoOptions\n /**\n * 기본 언어. 호스트에 @nuxtjs/i18n 이 있으면 그 언어를 따르고,\n * 보드 설정에서 언어를 고르면 그 보드는 그 언어로 고정된다. 기본 'ko'.\n */\n roleLabels?: Partial<Record<BoardUserRole, string>>\n locale?: string\n}\n\nconst GLOBAL_KEY = '__MEMI_BOARD_CONFIG__' as const\n\nfunction getSharedConfig(): MemiBoardConfig {\n const g = globalThis as typeof globalThis & {\n [GLOBAL_KEY]?: MemiBoardConfig\n }\n if (!g[GLOBAL_KEY]) {\n g[GLOBAL_KEY] = reactive<MemiBoardConfig>({\n postsCollection: DEFAULT_POSTS_COLLECTION,\n commentsCollection: DEFAULT_COMMENTS_COLLECTION,\n likesCollection: DEFAULT_LIKES_COLLECTION,\n reportsCollection: DEFAULT_REPORTS_COLLECTION,\n settingsCollection: DEFAULT_SETTINGS_COLLECTION,\n usersCollection: DEFAULT_USERS_COLLECTION,\n auth: { providers: ['google', 'apple'] },\n moderation: {\n enabled: true,\n model: 'gemini-3.5-flash-lite',\n onError: 'allow',\n moderateImages: false,\n localBlocklist: [],\n blockBanThreshold: 10,\n blockBanDecayMs: 24 * 60 * 60 * 1000,\n },\n seo: {\n enabled: true,\n siteName: 'Board',\n siteUrl: '',\n defaultOgImage: '',\n basePath: '/board',\n },\n })\n }\n return g[GLOBAL_KEY]\n}\n\nexport function configureMemiBoard(options: Partial<MemiBoardConfig>): void {\n const config = getSharedConfig()\n if (options.postsCollection != null && options.postsCollection !== '') {\n config.postsCollection = options.postsCollection.trim()\n }\n if (options.commentsCollection != null && options.commentsCollection !== '') {\n config.commentsCollection = options.commentsCollection.trim()\n }\n if (options.likesCollection != null && options.likesCollection !== '') {\n config.likesCollection = options.likesCollection.trim()\n }\n if (options.reportsCollection != null && options.reportsCollection !== '') {\n config.reportsCollection = options.reportsCollection.trim()\n }\n if (options.settingsCollection != null && options.settingsCollection !== '') {\n config.settingsCollection = options.settingsCollection.trim()\n }\n if (options.usersCollection != null && options.usersCollection !== '') {\n config.usersCollection = options.usersCollection.trim()\n }\n if (options.auth) Object.assign(config.auth, options.auth)\n if (options.moderation) Object.assign(config.moderation, options.moderation)\n if (options.seo) Object.assign(config.seo, options.seo)\n if (options.roleLabels) config.roleLabels = { ...options.roleLabels }\n if (options.locale) config.locale = options.locale\n}\n\nexport function useMemiBoardConfig(): MemiBoardConfig {\n return getSharedConfig()\n}\n\nexport function useBoardPathConfig(): BoardPathConfig {\n return resolveBoardPathConfig(useMemiBoardConfig())\n}\n","/** 게시판 UI 지원 언어. 코드는 @nuxtjs/i18n 호스트의 locale code 와 맞춘다. */\nexport const MEMI_BOARD_LOCALES = [\n { code: 'ko', name: '한국어', intl: 'ko-KR', dir: 'ltr' },\n { code: 'en', name: 'English', intl: 'en-US', dir: 'ltr' },\n { code: 'ja', name: '日本語', intl: 'ja-JP', dir: 'ltr' },\n { code: 'de', name: 'Deutsch', intl: 'de-DE', dir: 'ltr' },\n { code: 'fr', name: 'Français', intl: 'fr-FR', dir: 'ltr' },\n { code: 'es', name: 'Español', intl: 'es-419', dir: 'ltr' },\n { code: 'pt', name: 'Português', intl: 'pt-BR', dir: 'ltr' },\n { code: 'zh', name: '中文', intl: 'zh-CN', dir: 'ltr' },\n { code: 'ar', name: 'العربية', intl: 'ar', dir: 'rtl' },\n { code: 'id', name: 'Indonesia', intl: 'id-ID', dir: 'ltr' },\n] as const\n\nexport type MemiBoardLocale = typeof MEMI_BOARD_LOCALES[number]['code']\nexport type MemiBoardLocaleInfo = typeof MEMI_BOARD_LOCALES[number]\n\nexport const DEFAULT_MEMI_BOARD_LOCALE: MemiBoardLocale = 'ko'\n/** 번역이 빠진 키(긴 안내문 등)를 채우는 언어. ko 는 원문이라 모든 키가 있다. */\nexport const FALLBACK_MEMI_BOARD_LOCALE: MemiBoardLocale = 'en'\n\nconst CODES = new Set<string>(MEMI_BOARD_LOCALES.map(item => item.code))\n\n/** 'en-US', 'pt_BR', 'zh-Hans' 같은 값을 지원 언어 코드로 맞춘다. 지원하지 않으면 undefined. */\nexport function normalizeMemiBoardLocale(value: unknown): MemiBoardLocale | undefined {\n if (typeof value !== 'string') return undefined\n const code = value.trim().toLowerCase().split(/[-_]/)[0]\n return code && CODES.has(code) ? code as MemiBoardLocale : undefined\n}\n\nexport function memiBoardLocaleInfo(locale: MemiBoardLocale): MemiBoardLocaleInfo {\n return MEMI_BOARD_LOCALES.find(item => item.code === locale) ?? MEMI_BOARD_LOCALES[0]\n}\n","export default {\n attach: '파일 첨부 ({count} / {max})',\n maxFiles: '최대 {max}개까지 첨부할 수 있습니다.',\n}\n","export default {\n writeRestricted: '콘텐츠 경고가 누적되어 글·댓글 작성이 잠시 제한됐어요.',\n writeRestrictedUntil: '콘텐츠 경고가 누적되어 글·댓글 작성이 잠시 제한됐어요. ({until})',\n strikeSuffix: ' (경고 {count}/{threshold})',\n strikeRestrictedUntil: ' 경고 {count}회가 되어 글·댓글 작성이 제한됩니다 ({until}).',\n strikeRestricted: ' 경고 {count}회가 되어 글·댓글 작성이 제한됩니다.',\n notInitialized: '[memi-board] Firebase Auth가 초기화되지 않았습니다.',\n}\n","export default {\n tooLong: '메모는 {max}자까지 작성할 수 있습니다.',\n}\n","export default {\n viewProfile: '프로필 보기',\n viewPosts: '작성글 보기',\n viewComments: '작성한 댓글 보기',\n memoAriaLabel: '이 작성자에 대한 메모',\n memoTitle: '나만 보는 메모',\n memoPlaceholder: '이 작성자에 대해 적어두기…',\n bad: '나쁨',\n good: '좋음',\n}\n","export default {\n title: '프로필 사진 자르기',\n description: '정사각형(1:1)으로 보여집니다. 영역을 맞춰 주세요.',\n hint: '드래그로 위치·확대 조절 · {size}×{size} 정사각 JPEG로 저장됩니다',\n confirm: '자르고 업로드',\n}\n","export default {\n signInRequired: '로그인이 필요합니다.',\n idAndNameRequired: '보드 ID와 이름을 입력해 주세요.',\n deleteIdRequired: '삭제할 게시판 ID가 필요합니다.',\n nameRequired: '보드 이름을 입력해 주세요.',\n}\n","export default {\n unsupportedRole: '지원하지 않는 역할입니다.',\n roleDescription: {\n owner: '관리자 지정과 서비스 전체를 관리합니다.',\n manager: '담당 게시판의 설정과 스태프 배정을 관리합니다.',\n admin: '사용자 역할, 게시판 설정과 모든 콘텐츠를 관리합니다.',\n staff: '담당 게시판의 게시글과 댓글을 관리합니다. 설정과 담당자 배정은 바꿀 수 없습니다.',\n user: '글과 댓글을 작성하고 본인이 작성한 콘텐츠만 수정·삭제할 수 있습니다.',\n },\n}\n","export default {\n empty: '아직 댓글이 없습니다.',\n emptyLiked: '좋아요를 받은 댓글이 아직 없습니다.',\n loadFailed: '목록을 불러오지 못했습니다: {error}',\n blinded: '관리자에 의해 블라인드된 댓글입니다.',\n}\n","export default {\n hiddenBoardDenied: '숨김 게시판에는 담당 스태프만 댓글을 남길 수 있습니다.',\n denied: '이 게시판에는 댓글쓰기 권한이 없습니다.',\n signInRequired: '로그인이 필요합니다.',\n writeRestricted: '콘텐츠 경고가 누적되어 글·댓글 작성이 잠시 제한됐어요.',\n moderationBlocked: '작성할 수 없는 내용이 포함되어 있습니다.',\n replyTo: '{name}님에게 답글',\n placeholder: '댓글을 입력하세요',\n submitReply: '답글 작성',\n submit: '댓글 작성',\n signInToComment: '댓글을 작성하려면 로그인이 필요합니다.',\n}\n","export default {\n editRestricted: '댓글 수정이 잠시 제한됐어요.',\n moderationBlocked: '작성할 수 없는 내용이 포함되어 있습니다.',\n editFailed: '댓글을 수정하지 못했습니다.',\n blindConfirm: '이 댓글을 블라인드하면 모든 사용자에게 본문 대신 블라인드 안내가 표시됩니다. 원문은 삭제되지 않으며 나중에 다시 해제할 수 있습니다.\\n\\n블라인드하시겠습니까?',\n unblindConfirm: '블라인드를 해제하면 댓글 원문이 모든 사용자에게 다시 표시됩니다.\\n\\n블라인드를 해제하시겠습니까?',\n blindFailed: '블라인드 상태를 변경하지 못했습니다.',\n likeFailed: '좋아요를 처리하지 못했습니다.',\n blinded: '관리자에 의해 블라인드된 댓글입니다.',\n edit: '댓글 수정',\n blind: '댓글 블라인드',\n unblind: '댓글 블라인드 해제',\n delete: '댓글 삭제',\n}\n","export default {\n loading: '댓글을 불러오고 있습니다',\n empty: '아직 댓글이 없습니다.',\n loadMore: '댓글 더보기',\n loadingMore: '댓글을 더 불러오고 있습니다',\n}\n","export default {\n deleteConfirm: '이 댓글을 삭제하시겠습니까?',\n deleteFailed: '댓글을 삭제하지 못했습니다.',\n hideReplies: '답글 숨기기',\n showReplies: '답글 {count}개',\n loadMoreReplies: '답글 더보기',\n}\n","export default {\n bodyRequired: '댓글 내용을 입력해 주세요.',\n bodyTooLong: '댓글은 {max}자까지 작성할 수 있습니다.',\n replyTargetNotFound: '답글 대상 댓글을 찾을 수 없습니다.',\n threadNotFound: '댓글 스레드를 찾을 수 없습니다.',\n hasRepliesCannotDelete: '답글이 있는 댓글은 현재 삭제할 수 없습니다.',\n}\n","/** 여러 화면이 함께 쓰는 짧은 문구. */\nexport default {\n action: {\n cancel: '취소',\n save: '저장',\n saved: '저장됨',\n edit: '수정',\n delete: '삭제',\n confirm: '확인',\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 owner: '최고 관리자',\n manager: '매니저',\n admin: '관리자',\n staff: '스태프',\n user: '사용자',\n },\n date: {\n justNow: '방금 전',\n fewSecondsAgo: '몇 초 전',\n checking: '시간 확인 중',\n createdAt: '생성시간: {time}',\n updatedAt: '수정시간: {time}',\n },\n}\n","export default {\n deleteConfirm: '이 게시글을 삭제하시겠습니까? 되돌릴 수 없습니다.',\n notFound: '게시글을 찾을 수 없습니다.',\n draftPreview: '미공개 미리보기',\n draftNotice: '아직 게시되지 않았습니다. 게시하기 전까지는 작성자만 볼 수 있어요.',\n publish: '게시하기',\n backToList: '목록으로 돌아가기',\n postNav: '게시글 이동',\n list: '목록',\n comments: '댓글',\n}\n","export default {\n titlePlaceholder: '제목',\n contentPlaceholder: '본문을 입력하세요… / 를 입력하면 블록 메뉴가 열립니다.',\n imageContentPlaceholder: '내용을 입력하세요…',\n tagsPlaceholder: '태그 입력 후 Enter',\n skipModeration: '비속어 필터 무시 (관리자)',\n submitEdit: '수정 완료',\n submitNext: '다음: 미리보기',\n apply: '적용',\n imageOptimizing: '이미지 최적화 및 업로드 중…',\n cover: {\n hint: '사진 {count}/{max} · 대표사진 선택 · 끌어 순서 변경 · 파일 드롭/붙여넣기로 추가',\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 urlHelp: 'HTTPS 주소만 사용할 수 있으며 원본 사이트에서 삭제되면 이미지도 표시되지 않습니다.',\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 translateAll: '10개 언어로 번역해 저장',\n translateSaved: '10개 언어로 저장했습니다. 다른 언어로 보면 번역이 보입니다.',\n translatePending: '10개 언어 번역을 준비했습니다. 글을 저장하면 함께 기록됩니다.',\n translateEmpty: '번역할 제목이나 본문을 먼저 입력해 주세요.',\n title: '본문에서 제목 만들기',\n custom: '커스텀 스타일로 바꾸기…',\n failed: 'AI 작업에 실패했습니다. 다시 시도해 주세요.',\n },\n youtubePrompt: 'YouTube 링크를 입력하세요.',\n errors: {\n coverMax: '사진은 최대 {max}장까지 올릴 수 있어요.',\n imageUrlRequired: '이미지 주소를 입력해 주세요.',\n imageUrlInvalid: '올바른 이미지 주소를 입력해 주세요.',\n imageUrlHttps: 'HTTPS 이미지 주소만 사용할 수 있습니다.',\n imageUrlCredentials: '로그인 정보가 포함된 주소는 사용할 수 없습니다.',\n imageTimeout: '이미지를 불러오는 데 시간이 너무 오래 걸립니다.',\n imageNotDisplayable: '표시할 수 없는 이미지입니다.',\n imageLoadFailed: '이미지를 불러올 수 없습니다. 주소나 외부 링크 허용 여부를 확인해 주세요.',\n editorNotReady: '에디터를 준비하지 못했습니다. 다시 시도해 주세요.',\n imageLinkFailed: '이미지 링크를 추가하지 못했습니다.',\n imageOnly: '이미지 파일만 업로드할 수 있습니다.',\n imageTooLarge: '원본 이미지는 {mb}MB 이하여야 합니다.',\n imageUploadFailed: '이미지 업로드에 실패했습니다.',\n pasteAsFile: '사진은 위 영역에 파일로 붙여넣거나 드래그해 주세요.',\n postNotFound: '게시글을 찾을 수 없습니다.',\n loadPermission: '글을 불러올 권한이 없습니다. 로그인 상태를 확인해 주세요.',\n loadFailed: '글을 불러오지 못했습니다: {message}',\n editPermission: '수정 권한이 없습니다. 본인이 작성한 글인지, 로그인이 유지되는지 확인해 주세요.',\n titleRequired: '제목을 입력해 주세요.',\n photoRequired: '사진을 한 장 이상 올려 주세요.',\n bodyRequired: '본문에 글자를 입력하거나 이미지를 첨부해 주세요.',\n signInRequired: '로그인이 필요합니다.',\n boardMissing: '게시판(보드)이 지정되지 않았습니다.',\n writeRestricted: '콘텐츠 경고가 누적되어 글·댓글 작성이 잠시 제한됐어요.',\n moderationBlocked: '게시할 수 없는 내용이 포함되어 있습니다.',\n },\n hint: {\n reviewing: '내용을 검토하는 중…',\n saving: '저장하는 중…',\n },\n}\n","export default {\n introduction: 'Nuxt 4와 Vue 3, TypeScript를 바탕으로 만들고 Nuxt UI와 Firebase로 글과 댓글을 자연스럽게 이어가는 게시판입니다.',\n info: {\n title: '게시판 정보',\n about: '이 게시판은',\n history: '버전 히스토리',\n },\n stack: {\n ui: '화면과 경험',\n data: '데이터와 로그인',\n writing: '글쓰기와 편의',\n },\n}\n","export default {\n signInRequired: '로그인이 필요합니다.',\n commentNotFound: '댓글을 찾을 수 없습니다.',\n}\n","export default {\n introduction: '이 게시판은 Nuxt 4와 Vue 3, TypeScript를 바탕으로 만들었어요. Nuxt UI와 Tailwind CSS로 편안한 화면을 구성하고, Firebase Firestore·Auth·Storage와 nuxt-vuefire로 글과 댓글을 자연스럽게 이어갑니다.',\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","export default {\n default: '일반',\n dense: '조밀',\n video: '영상',\n}\n","export default {\n empty: '아직 댓글이 없습니다.',\n blinded: '관리자에 의해 블라인드된 댓글입니다.',\n}\n","export default {\n empty: '아직 글이 없습니다.',\n}\n","export default {\n selectedCount: '고른 글 {count} / {max}',\n layoutHint: '2개부터 캐러셀, 4개는 그리드',\n searchPlaceholder: '제목 검색',\n loading: '글을 불러오는 중…',\n noMore: '더 고를 글이 없습니다.',\n}\n","export default {\n empty: '고른 게시물이 없습니다.',\n}\n","export default {\n reviewFailed: '내용 검토에 실패해 글을 등록할 수 없습니다. 잠시 후 다시 시도해 주세요.',\n writeRestricted: '콘텐츠 경고가 누적되어 글·댓글 작성이 잠시 제한됐어요.',\n}\n","export default {\n localHit: '「{hit}」 같은 표현은 사용할 수 없습니다. 다른 말로 바꿔 주세요.',\n localGeneric: '욕설·비속어가 포함되어 게시할 수 없습니다. 표현을 바꿔 주세요.',\n categoryBlocked: '{category}이(가) 포함되어 게시할 수 없습니다. 내용을 수정해 주세요.',\n genericBlocked: '게시할 수 없는 내용이 포함되어 있습니다. 내용을 수정해 주세요.',\n categories: {\n abuse: '욕설·비속어·모욕',\n spam: '스팸·광고',\n adult: '선정적·성인 내용',\n violence: '폭력·위협',\n other: '부적절한 내용',\n },\n}\n","export default {\n liftSoon: '곧 해제',\n liftInHours: '약 {hours}시간 후 해제',\n liftInDays: '약 {days}일 후 해제',\n liftInDaysHours: '약 {days}일 {hours}시간 후 해제',\n}\n","export default {\n boardIdRequired: '[memi-board] boardId 가 필요합니다.',\n photoRequired: '사진을 올려 주세요.',\n bodyRequired: '본문에 글자를 입력하거나 이미지를 첨부해 주세요.',\n titleRequired: '제목을 입력해 주세요.',\n}\n","export default {\n notFound: '사용자를 찾을 수 없습니다.',\n noName: '이름 없음',\n joined: '가입 {time}',\n lastVisit: '최근 방문 {time}',\n}\n","export default {\n imageOnly: '이미지 파일만 선택할 수 있습니다.',\n nameRequired: '이름을 입력해 주세요.',\n saveFailed: '프로필을 저장하지 못했습니다.',\n title: '프로필 수정',\n changePhoto: '사진 변경',\n name: '이름',\n bio: '자기소개',\n bioPlaceholder: '나를 소개해 보세요',\n}\n","export default {\n failed: '신고하지 못했습니다.',\n reported: '신고함',\n title: '게시물 신고',\n done: '신고를 접수했습니다. 스태프가 내용을 확인합니다.',\n reason: '사유',\n detailPlaceholder: '자세한 내용 (선택)',\n submit: '신고하기',\n}\n","export default {\n staffOnly: '스태프만 신고 목록을 볼 수 있습니다.',\n loadFailed: '목록을 불러오지 못했습니다: {error}',\n empty: '대기 중인 신고가 없습니다.',\n untitled: '제목 없는 글',\n author: '작성 {name}',\n dismiss: '기각',\n confirm: '확인',\n}\n","export default {\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","export default {\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","export default {\n defaultTitle: '섹션 {n}',\n}\n","export default {\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","export default {\n managers: '담당 매니저',\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: '주소와 데이터 기준값',\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 hiddenHelp: '숨김 게시판은 댓글이 공개 피드에 안 나오고, 담당 스태프만 작성할 수 있습니다',\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 pending: '공개 범위 변경이 아직 끝나지 않았습니다. 같은 설정으로 다시 저장하면 이어서 처리합니다.',\n label: '공개 범위',\n help: '숨김이면 전체 필터에 안 나오고, 글은 관리자·담당 스태프·작성자만 읽을 수 있습니다. 댓글은 담당 스태프만 쓸 수 있습니다',\n options: {\n public: { label: '보임', description: '전체 목록·필터에 표시' },\n hidden: { label: '숨김', description: '일기장·비공개. 댓글은 담당 스태프만' },\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 help: '비우면 사이트 언어를 따릅니다. 고르면 이 게시판은 항상 그 언어로 보입니다.',\n auto: '자동 (사이트 언어 따름)',\n },\n autoTranslate: {\n action: \"10개 언어로 번역\",\n manualHelp: \"표시 라벨과 설명을 함께 번역합니다. 번역 후 저장 버튼을 눌러 적용하세요.\",\n pending: \"10개 언어 번역이 준비되었습니다. 저장 버튼을 눌러 적용하세요.\",\n manualFailed: \"번역하지 못했습니다. 입력한 내용은 유지됩니다. 다시 시도해 주세요.\",\n label: '저장할 때 10개 언어로 번역',\n help: '켜 두면 이름과 설명을 10개 언어로 번역합니다. 꺼져 있으면 번역하지 않습니다. 문구가 그대로면 다시 번역하지 않습니다.',\n failed: '설정은 저장했지만 10개 언어 번역에 실패했습니다. 다시 저장해 주세요.',\n ready: '이름과 설명이 10개 언어로 저장되어 있습니다.',\n },\n action: {\n moveDown: '아래로',\n goToBoard: '게시판으로 이동',\n deleteBoard: '게시판 삭제',\n create: '만들기',\n },\n newCategoryPlaceholder: '새 카테고리 이름',\n deleteConfirm: '‘{label}’ 게시판을 삭제하시겠습니까?\\n\\n이 게시판의 모든 게시물, 댓글, 대댓글, 본문 이미지와 첨부파일이 영구 삭제됩니다. 이 작업은 되돌릴 수 없습니다.',\n savedCategory: '‘{label}’ 카테고리를 저장했습니다.',\n savedSettings: '게시판 설정을 저장했습니다.',\n created: '게시판을 만들었습니다.',\n error: {\n orderFailed: '카테고리 순서를 저장하지 못했습니다.',\n deleteFailed: '게시판과 연결 데이터를 삭제하지 못했습니다.',\n saveFailed: '게시판 설정을 저장하지 못했습니다.',\n deleteAllFailed: '게시판 데이터를 삭제하지 못했습니다.',\n },\n danger: {\n title: '위험 영역',\n description: '모든 게시글, 댓글, 첨부파일과 카테고리 설정을 영구 삭제합니다. 게시판 사용자와 관리자 권한은 유지합니다.',\n confirmLabel: '확인을 위해 ‘{phrase}’를 입력하세요',\n phrase: '게시판 데이터 삭제',\n button: '모든 데이터 삭제',\n done: '게시판 데이터를 모두 삭제했습니다.',\n },\n}\n","export default {\n copied: '링크 복사됨',\n}\n","export default {\n withGoogle: 'Google로 로그인',\n withApple: 'Apple로 로그인',\n or: '또는',\n name: '이름',\n email: '이메일',\n password: '비밀번호',\n signUp: '회원가입',\n toSignUp: '계정이 없으신가요? 회원가입',\n toSignIn: '이미 계정이 있으신가요? 로그인',\n}\n","export default {\n tooLargeAfterCompress: '압축 후에도 이미지가 5MB를 초과합니다. 더 작은 이미지를 선택해 주세요.',\n sourceTooLarge: '원본 이미지는 {max}MB 이하여야 합니다.',\n heicUnsupported: 'HEIC 사진은 바로 올릴 수 없습니다. 사진 앱에서 선택하거나 JPG, PNG 또는 WebP로 변환해 주세요.',\n cannotOptimize: '이 이미지 형식은 브라우저에서 최적화할 수 없습니다. JPG, PNG 또는 WebP로 변환해 주세요.',\n imageOnly: '이미지 파일만 업로드할 수 있습니다.',\n canvasUnavailable: 'Canvas를 사용할 수 없습니다',\n compressFailed: '압축 실패',\n loadFailed: '이미지 로드 실패',\n}\n","export default {\n title: '좌우로 스와이프해 보세요',\n description: '왼쪽으로 밀면 다음 글, 오른쪽으로 밀면 이전 글로 이동해요.',\n}\n","export default {\n loadFailed: '목록을 불러오지 못했습니다: {error}',\n empty: '작성한 댓글이 없습니다.',\n blinded: '관리자에 의해 블라인드된 댓글입니다.',\n likes: '좋아요 {count}',\n}\n","export default {\n loadFailed: '목록을 불러오지 못했습니다: {error}',\n empty: '작성한 글이 없습니다.',\n}\n","export default {\n changeRoleFailed: '역할을 변경하지 못했습니다.',\n loading: '사용자 목록을 불러오고 있습니다.',\n noPermission: {\n title: '권한이 없습니다',\n description: '게시판 관리자만 사용자 역할을 관리할 수 있습니다.',\n },\n empty: '게시판에 로그인한 사용자가 없습니다.',\n noName: '이름 없음',\n moderationWarnings: '콘텐츠 경고 {count}회',\n}\n","export default {\n loginRequired: 'AI 글쓰기 도우미는 로그인 후 사용할 수 있습니다.',\n userMissing: '사용자 정보를 확인한 뒤 다시 시도해 주세요.',\n dailyLimit: 'AI 글쓰기 도우미는 하루 {limit}회까지 사용할 수 있습니다. 약 {hours}시간 후 다시 이용해 주세요.',\n contentRequired: 'AI로 다듬을 내용을 먼저 입력해 주세요.',\n customRequired: '어떻게 바꿀지 지시문을 입력해 주세요.',\n emptyResult: 'AI가 결과를 만들지 못했습니다. 다시 시도해 주세요.',\n translateEmpty: '번역할 제목이나 본문을 먼저 입력해 주세요.',\n translateTooLong: '본문이 {limit}자를 넘으면 10개 언어로 저장할 수 없습니다. 줄인 뒤 다시 시도해 주세요.',\n translateIncomplete: '일부 언어 번역이 비었습니다. 다시 시도해 주세요.',\n failed: 'AI 작업에 실패했습니다. 다시 시도해 주세요.',\n actions: {\n proofread: '맞춤법 검사',\n polish: '문장 다듬기',\n continue: '자연스럽게 이어쓰기',\n summarize: '짧게 요약하기',\n translateEn: '영어로 번역',\n translateKo: '한국어로 번역',\n translateAll: '10개 언어로 번역해 저장',\n title: '본문에서 제목 만들기',\n custom: '커스텀 스타일로 바꾸기…',\n },\n}\n","// 자동 생성 — scripts/gen-i18n-index.mjs\nimport attachments from './attachments'\nimport auth from './auth'\nimport authorMemo from './authorMemo'\nimport authorMenu from './authorMenu'\nimport avatarCropModal from './avatarCropModal'\nimport boardSettings from './boardSettings'\nimport boardUsers from './boardUsers'\nimport commentFeed from './commentFeed'\nimport commentForm from './commentForm'\nimport commentItem from './commentItem'\nimport commentList from './commentList'\nimport commentThread from './commentThread'\nimport comments from './comments'\nimport common from './common'\nimport detail from './detail'\nimport editor from './editor'\nimport footer from './footer'\nimport likes from './likes'\nimport list from './list'\nimport listViewSwitch from './listViewSwitch'\nimport miniComments from './miniComments'\nimport miniList from './miniList'\nimport miniPicker from './miniPicker'\nimport miniPost from './miniPost'\nimport moderation from './moderation'\nimport moderationPrompt from './moderationPrompt'\nimport moderationStrike from './moderationStrike'\nimport posts from './posts'\nimport profile from './profile'\nimport profileEditModal from './profileEditModal'\nimport reportButton from './reportButton'\nimport reportList from './reportList'\nimport reports from './reports'\nimport sectionUtil from './sectionUtil'\nimport sections from './sections'\nimport seo from './seo'\nimport settings from './settings'\nimport shareButton from './shareButton'\nimport signIn from './signIn'\nimport storage from './storage'\nimport swipeHint from './swipeHint'\nimport userCommentList from './userCommentList'\nimport userPostList from './userPostList'\nimport users from './users'\nimport writingAssistant from './writingAssistant'\n\nexport default {\n attachments,\n auth,\n authorMemo,\n authorMenu,\n avatarCropModal,\n boardSettings,\n boardUsers,\n commentFeed,\n commentForm,\n commentItem,\n commentList,\n commentThread,\n comments,\n common,\n detail,\n editor,\n footer,\n likes,\n list,\n listViewSwitch,\n miniComments,\n miniList,\n miniPicker,\n miniPost,\n moderation,\n moderationPrompt,\n moderationStrike,\n posts,\n profile,\n profileEditModal,\n reportButton,\n reportList,\n reports,\n sectionUtil,\n sections,\n seo,\n settings,\n shareButton,\n signIn,\n storage,\n swipeHint,\n userCommentList,\n userPostList,\n users,\n writingAssistant,\n}\n","import { shallowRef, type Ref } from 'vue'\nimport {\n DEFAULT_MEMI_BOARD_LOCALE,\n FALLBACK_MEMI_BOARD_LOCALE,\n type MemiBoardLocale,\n} from './locales'\nimport ko from './messages/ko'\n\nexport interface MemiBoardMessages {\n [key: string]: string | MemiBoardMessages\n}\n\nexport type MemiBoardMessageParams = Record<string, string | number | null | undefined>\n\n/**\n * 언어별 번역은 필요할 때만 받는다(언어당 별도 청크).\n * ko 는 원문이자 최종 폴백이라 코어 번들에 들어간다.\n */\nconst loaders: Record<Exclude<MemiBoardLocale, 'ko'>, () => Promise<{ default: MemiBoardMessages }>> = {\n en: () => import('./messages/en'),\n ja: () => import('./messages/ja'),\n de: () => import('./messages/de'),\n fr: () => import('./messages/fr'),\n es: () => import('./messages/es'),\n pt: () => import('./messages/pt'),\n zh: () => import('./messages/zh'),\n ar: () => import('./messages/ar'),\n id: () => import('./messages/id'),\n}\n\nconst GLOBAL_KEY = '__MEMI_BOARD_I18N__' as const\n\ninterface I18nStore {\n messages: Partial<Record<MemiBoardLocale, MemiBoardMessages>>\n pending: Partial<Record<MemiBoardLocale, Promise<void>>>\n /** 언어 파일이 도착하면 올라가서 t() 를 쓰는 화면을 다시 그린다. */\n version: Ref<number>\n}\n\nfunction store(): I18nStore {\n const g = globalThis as typeof globalThis & { [GLOBAL_KEY]?: I18nStore }\n g[GLOBAL_KEY] ??= { messages: { ko }, pending: {}, version: shallowRef(0) }\n return g[GLOBAL_KEY]\n}\n\nfunction loadOne(locale: MemiBoardLocale): Promise<void> {\n const s = store()\n if (s.messages[locale]) return Promise.resolve()\n if (locale === 'ko') return Promise.resolve()\n s.pending[locale] ??= loaders[locale]()\n .then((mod) => {\n s.messages[locale] = mod.default\n s.version.value++\n })\n .catch((error) => {\n delete s.pending[locale]\n console.warn(`[memi-board] failed to load locale \"${locale}\"`, error)\n })\n return s.pending[locale]!\n}\n\n/** 해당 언어와 폴백(en) 번역을 받아 둔다. 이미 받았으면 바로 끝난다. */\nexport function loadMemiBoardLocale(locale: MemiBoardLocale): Promise<void> {\n if (locale === 'ko') return Promise.resolve()\n return Promise.all([loadOne(locale), loadOne(FALLBACK_MEMI_BOARD_LOCALE)]).then(() => undefined)\n}\n\nexport function isMemiBoardLocaleLoaded(locale: MemiBoardLocale): boolean {\n return !!store().messages[locale]\n}\n\nfunction lookup(tree: MemiBoardMessages | undefined, key: string): string | undefined {\n let node: string | MemiBoardMessages | undefined = tree\n for (const part of key.split('.')) {\n if (!node || typeof node === 'string') return undefined\n node = node[part]\n }\n return typeof node === 'string' ? node : undefined\n}\n\nfunction interpolate(text: string, params?: MemiBoardMessageParams): string {\n if (!params) return text\n return text.replace(/\\{(\\w+)\\}/g, (match, name: string) => {\n const value = params[name]\n return value == null ? match : String(value)\n })\n}\n\n/**\n * 키 하나를 번역한다. 언어 → en → ko 순으로 찾는다.\n * 아직 받지 않은 언어는 건너뛰므로, 파일이 오기 전 잠깐은 폴백 문구가 보일 수 있다.\n * 반응형 의존성을 걸어 두어 파일이 도착하면 다시 계산된다.\n */\nexport function translate(\n locale: MemiBoardLocale | undefined,\n key: string,\n params?: MemiBoardMessageParams,\n): string {\n const s = store()\n void s.version.value\n const code = locale ?? DEFAULT_MEMI_BOARD_LOCALE\n const text = lookup(s.messages[code], key)\n ?? (code === 'ko' ? undefined : lookup(s.messages[FALLBACK_MEMI_BOARD_LOCALE], key))\n ?? lookup(s.messages.ko, key)\n return text == null ? key : interpolate(text, params)\n}\n","import type { Timestamp } from 'firebase/firestore'\nimport { DEFAULT_MEMI_BOARD_LOCALE, memiBoardLocaleInfo, type MemiBoardLocale } from '../i18n/locales'\nimport { translate } from '../i18n/translate'\n\nfunction intl(locale: MemiBoardLocale | undefined): string {\n return memiBoardLocaleInfo(locale ?? DEFAULT_MEMI_BOARD_LOCALE).intl\n}\n\nexport function formatDate(ts: Timestamp | undefined, locale?: MemiBoardLocale): string {\n return ts?.toDate ? ts.toDate().toLocaleDateString(intl(locale)) : ''\n}\n\nconst MINUTE = 60\nconst HOUR = 60 * MINUTE\nconst DAY = 24 * HOUR\n\n/** dayjs relativeTime 기본 구간과 같은 기준으로 반올림한다. */\nexport function formatRelativeDate(ts: Timestamp | undefined, now = Date.now(), locale?: MemiBoardLocale): string {\n if (!ts?.toDate) return translate(locale, 'common.date.justNow')\n const seconds = Math.max(0, Math.round((now - ts.toDate().getTime()) / 1000))\n if (seconds < 45) return translate(locale, 'common.date.fewSecondsAgo')\n const rtf = new Intl.RelativeTimeFormat(intl(locale), { numeric: 'always' })\n const days = seconds / DAY\n if (seconds < 90) return rtf.format(-1, 'minute')\n if (seconds < 45 * MINUTE) return rtf.format(-Math.round(seconds / MINUTE), 'minute')\n if (seconds < 90 * MINUTE) return rtf.format(-1, 'hour')\n if (seconds < 22 * HOUR) return rtf.format(-Math.round(seconds / HOUR), 'hour')\n if (seconds < 36 * HOUR) return rtf.format(-1, 'day')\n if (days < 26) return rtf.format(-Math.round(days), 'day')\n if (days < 46) return rtf.format(-1, 'month')\n if (days < 320) return rtf.format(-Math.round(days / 30.4), 'month')\n if (days < 548) return rtf.format(-1, 'year')\n return rtf.format(-Math.round(days / 365), 'year')\n}\n\nexport function formatFullDate(ts: Timestamp | undefined, locale?: MemiBoardLocale): string {\n if (!ts?.toDate) return translate(locale, 'common.date.checking')\n return new Intl.DateTimeFormat(intl(locale), {\n year: 'numeric',\n month: 'long',\n day: 'numeric',\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n hourCycle: 'h23',\n }).format(ts.toDate())\n}\n\n/** 생성·수정 시각이 같거나 수정 시각이 없으면 한 줄, 실제 수정됐으면 두 줄. */\nexport function formatTimestampDetails(\n createdAt: Timestamp | undefined,\n updatedAt?: Timestamp,\n locale?: MemiBoardLocale,\n): string[] {\n const created = formatFullDate(createdAt, locale)\n const createdMs = createdAt?.toMillis?.()\n const updatedMs = updatedAt?.toMillis?.()\n if (updatedMs == null || createdMs == null || createdMs === updatedMs) return [created]\n return [\n translate(locale, 'common.date.createdAt', { time: created }),\n translate(locale, 'common.date.updatedAt', { time: formatFullDate(updatedAt, locale) }),\n ]\n}\n","import {\n computed,\n getCurrentInstance,\n hasInjectionContext,\n inject,\n onServerPrefetch,\n provide,\n toValue,\n watch,\n type ComputedRef,\n type InjectionKey,\n type MaybeRefOrGetter,\n} from 'vue'\nimport { useMemiBoardConfig } from '../config'\nimport {\n DEFAULT_MEMI_BOARD_LOCALE,\n memiBoardLocaleInfo,\n normalizeMemiBoardLocale,\n type MemiBoardLocale,\n} from './locales'\nimport { loadMemiBoardLocale, translate, type MemiBoardMessageParams } from './translate'\nimport {\n formatDate,\n formatFullDate,\n formatRelativeDate,\n formatTimestampDetails,\n} from '../utils/formatDate'\nimport type { Timestamp } from 'firebase/firestore'\n\n/**\n * 호스트 언어. memi-board Nuxt 플러그인이 @nuxtjs/i18n 의 locale 을 앱 단위로 provide 한다.\n * 문자열 키 — dist 번들과 호스트 컴파일 플러그인이 같은 키를 보게 한다.\n */\nexport const memiBoardHostLocaleKey = 'memiBoard:hostLocale' as unknown as InjectionKey<MaybeRefOrGetter<string | undefined | null>>\n/** 보드 단위 언어. 보드 화면(List·Detail·Editor)이 provide 하고 자식(댓글 등)이 따른다. */\nconst boardLocaleKey: InjectionKey<ComputedRef<MemiBoardLocale>> = Symbol('memiBoard:boardLocale')\n\nexport interface UseMemiBoardI18nOptions {\n /**\n * 보드 설정의 언어(`BoardModel.locale`). 비어 있으면 호스트 언어를 따른다.\n * 넘기면 이 컴포넌트 아래 자식들도 같은 언어를 쓴다.\n */\n boardLocale?: MaybeRefOrGetter<string | undefined | null>\n}\n\nexport function useMemiBoardI18n(options: UseMemiBoardI18nOptions = {}) {\n const canInject = hasInjectionContext()\n const parentLocale = canInject ? inject(boardLocaleKey, null) : null\n const hostLocale = canInject ? inject(memiBoardHostLocaleKey, null) : null\n const config = useMemiBoardConfig()\n\n const locale = computed<MemiBoardLocale>(() =>\n normalizeMemiBoardLocale(toValue(options.boardLocale))\n ?? parentLocale?.value\n ?? normalizeMemiBoardLocale(toValue(hostLocale))\n ?? normalizeMemiBoardLocale(config.locale)\n ?? DEFAULT_MEMI_BOARD_LOCALE,\n )\n\n if (options.boardLocale !== undefined && canInject) provide(boardLocaleKey, locale)\n\n watch(locale, value => void loadMemiBoardLocale(value), { immediate: true })\n if (getCurrentInstance()) onServerPrefetch(() => loadMemiBoardLocale(locale.value))\n\n const info = computed(() => memiBoardLocaleInfo(locale.value))\n\n return {\n locale,\n /** 'ltr' | 'rtl' — 보드 루트 요소의 dir 속성에 쓴다. */\n dir: computed(() => info.value.dir),\n /** Intl 로케일 태그(예: 'ko-KR'). */\n intlLocale: computed(() => info.value.intl),\n t: (key: string, params?: MemiBoardMessageParams) => {\n const role = key.startsWith('common.role.') ? key.slice('common.role.'.length) : ''\n return config.roleLabels?.[role as keyof NonNullable<typeof config.roleLabels>] ?? translate(locale.value, key, params)\n },\n formatDate: (ts: Timestamp | undefined) => formatDate(ts, locale.value),\n formatFullDate: (ts: Timestamp | undefined) => formatFullDate(ts, locale.value),\n formatRelativeDate: (ts: Timestamp | undefined, now?: number) => formatRelativeDate(ts, now, locale.value),\n formatTimestampDetails: (createdAt: Timestamp | undefined, updatedAt?: Timestamp) =>\n formatTimestampDetails(createdAt, updatedAt, locale.value),\n /** 숫자를 현재 언어 형식으로(예: 1,234). */\n formatNumber: (value: number) => value.toLocaleString(info.value.intl),\n }\n}\n\nexport type MemiBoardI18n = ReturnType<typeof useMemiBoardI18n>\n","/**\n * 제목 문자열을 URL-friendly slug로 변환\n * e.g. \"게시판 모듈 만들기!!\" → \"게시판-모듈-만들기\"\n */\nexport function slugify(text: string): string {\n return text\n .trim()\n .replace(/\\s+/g, '-') // 공백(연속 포함) → 하이픈\n .replace(/[^a-zA-Z0-9가-힣ㄱ-ㅎㅏ-ㅣ-]/g, '') // 허용 문자 외 제거\n .replace(/-+/g, '-') // 연속 하이픈 → 단일 하이픈\n .replace(/^-+|-+$/g, '') // 앞뒤 하이픈 제거\n}\n\n/** Storage 경로/파일명에 안전한 문자열로 변환 (한글은 유지) */\nexport function safeFileName(name: string, maxLength = 60): string {\n return name.replace(/[^a-zA-Z0-9가-힣ㄱ-ㅎ._-]/g, '-').slice(0, maxLength)\n}\n"],"mappings":"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"}
package/dist/storage.js CHANGED
@@ -1,4 +1,4 @@
1
- import { R as e, d as t, i as n, t as r, v as i } from "./slugify-DJ82ifCd.js";
1
+ import { R as e, d as t, i as n, t as r, v as i } from "./slugify-B05Qykf_.js";
2
2
  import { useFirebaseApp as a } from "vuefire";
3
3
  import { getAuth as o } from "firebase/auth";
4
4
  import { deleteObject as s, getDownloadURL as c, getStorage as l, ref as u, uploadBytes as d, uploadBytesResumable as f } from "firebase/storage";
package/dist/types.d.ts CHANGED
@@ -1,4 +1,31 @@
1
1
  import { Timestamp } from 'firebase/firestore';
2
+ import { MemiBoardLocale } from './i18n/locales';
3
+ /** 언어별 필드 번역. `{ en: { title: '…' }, ja: { title: '…' } }` */
4
+ export type MemiBoardI18nMap = Partial<Record<MemiBoardLocale, Record<string, string>>>;
5
+ /**
6
+ * 번역을 만든 시점의 원문. 이 값과 문서의 원문 필드가 같을 때만 번역을 보여 준다.
7
+ * 게시판은 label·description, 글은 title·summary, 섹션은 title 만 채운다.
8
+ */
9
+ export interface MemiBoardI18nSource {
10
+ locale?: MemiBoardLocale;
11
+ label?: string;
12
+ description?: string;
13
+ title?: string;
14
+ summary?: string;
15
+ contentHash?: string;
16
+ }
17
+ /** 본문 서브문서에 두는 번역 기준. 본문 전체 대신 해시만 저장한다. */
18
+ export interface PostContentI18nSource {
19
+ locale?: MemiBoardLocale;
20
+ hash?: string;
21
+ }
22
+ /** 글 제목·요약·본문을 10개 언어로 저장한 결과. */
23
+ export interface PostTranslationSet {
24
+ i18n: MemiBoardI18nMap;
25
+ i18nSource: MemiBoardI18nSource;
26
+ contentI18n?: MemiBoardI18nMap;
27
+ contentI18nSource?: PostContentI18nSource;
28
+ }
2
29
  export interface Attachment {
3
30
  name: string;
4
31
  url: string;
@@ -67,9 +94,17 @@ export interface PostModel {
67
94
  moderationModel?: string;
68
95
  createdAt: Timestamp;
69
96
  updatedAt: Timestamp;
97
+ /** 제목·요약의 10개 언어 번역. 본문은 body/main 에 따로 둔다. */
98
+ i18n?: MemiBoardI18nMap;
99
+ /** 번역을 만들 때의 제목·요약. 지금 원문과 다르면 번역을 쓰지 않는다. */
100
+ i18nSource?: MemiBoardI18nSource;
70
101
  }
71
102
  export interface PostDetail extends PostModel {
72
103
  content: string;
104
+ /** body/main 의 본문 번역. */
105
+ contentI18n?: MemiBoardI18nMap;
106
+ /** 본문 번역을 만든 시점의 해시. 본문이 바뀌면 번역을 쓰지 않는다. */
107
+ contentI18nSource?: PostContentI18nSource;
73
108
  }
74
109
  /**
75
110
  * @deprecated PostModel 에 boardId 가 이미 있어 더 이상 별도 타입이 필요 없다.
@@ -182,6 +217,15 @@ export interface BoardModel {
182
217
  * 게시판 화면 언어(MEMI_BOARD_LOCALES 코드). 비어 있으면 호스트 언어를 따른다.
183
218
  */
184
219
  locale?: string;
220
+ /** 이름·설명의 10개 언어 번역. */
221
+ i18n?: MemiBoardI18nMap;
222
+ /** 번역을 만들 때의 이름·설명. */
223
+ i18nSource?: MemiBoardI18nSource;
224
+ /**
225
+ * 설정을 저장할 때 이름·설명을 10개 언어로 번역한다.
226
+ * 없거나 false 이면 번역하지 않는다.
227
+ */
228
+ autoTranslate?: boolean;
185
229
  /** 보드 목록 정렬 */
186
230
  order?: number;
187
231
  }
@@ -209,6 +253,10 @@ export interface BoardSection {
209
253
  cols: BoardSectionCols;
210
254
  height: BoardSectionHeight;
211
255
  order: number;
256
+ /** 섹션 제목의 10개 언어 번역. */
257
+ i18n?: MemiBoardI18nMap;
258
+ /** 번역을 만들 때의 제목. */
259
+ i18nSource?: MemiBoardI18nSource;
212
260
  }
213
261
  export interface BoardSectionLayout {
214
262
  columns: 12;
@@ -0,0 +1,33 @@
1
+ import { MemiBoardLocale } from '../i18n/locales';
2
+ import { MemiBoardI18nMap, MemiBoardI18nSource, PostContentI18nSource, PostDetail, PostModel } from '../types';
3
+ /** 본문처럼 긴 문자열이 번역 당시와 같은지 비교할 때 쓴다. */
4
+ export declare function hashText(value: string): string;
5
+ /** Firestore에 넣은 i18n 맵만 남긴다. 지원하지 않는 키와 빈 문자열은 버린다. */
6
+ export declare function readLocalizedFields(value: unknown): MemiBoardI18nMap | undefined;
7
+ export declare function readI18nSource(value: unknown): MemiBoardI18nSource | undefined;
8
+ export declare function readContentI18nSource(value: unknown): PostContentI18nSource | undefined;
9
+ /** 모델 결과에 원문 언어 값을 합쳐 10개 언어가 모두 있게 만든다. */
10
+ export declare function mergeSourceFields(source: MemiBoardLocale, fields: Record<string, string>, translated: MemiBoardI18nMap | undefined): MemiBoardI18nMap;
11
+ /** 지원 언어 10개 모두 해당 필드를 가졌는지. */
12
+ export declare function coversLocales(i18n: MemiBoardI18nMap | undefined, fields: string[]): boolean;
13
+ /**
14
+ * 저장된 번역에서 현재 언어 값을 고른다.
15
+ * 원문 언어로 볼 때는 번역 대신 fallback(원문 필드)을 쓴다.
16
+ * 그 외에는 현재 언어 → en → 원문 순.
17
+ */
18
+ export declare function localizedText(i18n: MemiBoardI18nMap | null | undefined, locale: string | null | undefined, field: string, fallback: string, sourceLocale?: string | null): string;
19
+ /**
20
+ * 원문 필드가 번역을 만들 때와 같을 때만 번역을 쓴다.
21
+ * 제목·이름·설명을 나중에 고치면 옛 번역 대신 원문이 보인다.
22
+ */
23
+ export declare function displayStoredField(i18n: MemiBoardI18nMap | null | undefined, i18nSource: MemiBoardI18nSource | null | undefined, field: 'label' | 'description' | 'title' | 'summary', current: string, locale?: string | null): string;
24
+ export declare function displayPostTitle(post: Pick<PostModel, 'title' | 'i18n' | 'i18nSource'>, locale?: string | null): string;
25
+ export declare function displayPostSummary(post: Pick<PostModel, 'summary' | 'i18n' | 'i18nSource'>, locale?: string | null): string;
26
+ /** 본문 해시가 번역 당시와 같을 때만 번역 HTML 을 돌려준다. */
27
+ export declare function displayPostContent(post: Pick<PostDetail, 'content' | 'contentI18n' | 'contentI18nSource'>, locale?: string | null): string;
28
+ export declare function boardCopyIsTranslated(board: {
29
+ label: string;
30
+ description?: string;
31
+ i18n?: MemiBoardI18nMap;
32
+ i18nSource?: MemiBoardI18nSource;
33
+ }): boolean;
@@ -246,6 +246,10 @@ var e = {
246
246
  summarize: "简短总结",
247
247
  translateEn: "翻译成英语",
248
248
  translateKo: "翻译成韩语",
249
+ translateAll: "翻译并保存为10种语言",
250
+ translateSaved: "已保存为10种语言。用其他语言查看时会看到译文。",
251
+ translatePending: "已准备好10种语言的翻译。保存文章时会一并记录。",
252
+ translateEmpty: "请先输入要翻译的标题或正文。",
249
253
  title: "根据正文生成标题",
250
254
  custom: "改写为自定义风格…",
251
255
  failed: "AI 处理失败,请重试。"
@@ -529,6 +533,16 @@ var e = {
529
533
  label: "版块语言",
530
534
  auto: "自动(跟随网站语言)"
531
535
  },
536
+ autoTranslate: {
537
+ action: "翻译为10种语言",
538
+ manualHelp: "一起翻译显示名称和说明,翻译后请点击保存以应用。",
539
+ pending: "10种语言的翻译已就绪,请点击保存以应用。",
540
+ manualFailed: "翻译失败,输入内容已保留,请重试。",
541
+ label: "保存时翻译成10种语言",
542
+ help: "打开后,保存时会把名称和说明翻译成10种语言。关闭时不翻译。文字没变就不会再次翻译。",
543
+ failed: "设置已保存,但翻译成10种语言失败了。请再次保存。",
544
+ ready: "名称和说明已保存为10种语言。"
545
+ },
532
546
  action: {
533
547
  moveDown: "下移",
534
548
  goToBoard: "前往版块",
@@ -603,6 +617,9 @@ var e = {
603
617
  contentRequired: "请先输入要让 AI 润色的内容。",
604
618
  customRequired: "请输入改写要求。",
605
619
  emptyResult: "AI 未能生成结果,请重试。",
620
+ translateEmpty: "请先输入要翻译的标题或正文。",
621
+ translateTooLong: "正文超过{limit}字时无法保存为10种语言。请缩短后再试。",
622
+ translateIncomplete: "部分语言的翻译是空的。请重试。",
606
623
  failed: "AI 处理失败,请重试。",
607
624
  actions: {
608
625
  proofread: "拼写检查",
@@ -611,6 +628,10 @@ var e = {
611
628
  summarize: "简短总结",
612
629
  translateEn: "翻译成英语",
613
630
  translateKo: "翻译成韩语",
631
+ translateAll: "翻译并保存为10种语言",
632
+ translateSaved: "已保存为10种语言。用其他语言查看时会看到译文。",
633
+ translatePending: "已准备好10种语言的翻译。保存文章时会一并记录。",
634
+ translateEmpty: "请先输入要翻译的标题或正文。",
614
635
  title: "根据正文生成标题",
615
636
  custom: "改写为自定义风格…"
616
637
  }
@@ -619,4 +640,4 @@ var e = {
619
640
  //#endregion
620
641
  export { e as default };
621
642
 
622
- //# sourceMappingURL=zh-D5rDYV6E.js.map
643
+ //# sourceMappingURL=zh-CMyzTdQ5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zh-CMyzTdQ5.js","names":[],"sources":["../src/i18n/messages/zh.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: '确定',\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 translateAll: '翻译并保存为10种语言',\n translateSaved: '已保存为10种语言。用其他语言查看时会看到译文。',\n translatePending: '已准备好10种语言的翻译。保存文章时会一并记录。',\n translateEmpty: '请先输入要翻译的标题或正文。',\n title: '根据正文生成标题',\n custom: '改写为自定义风格…',\n failed: 'AI 处理失败,请重试。',\n },\n youtubePrompt: '请输入 YouTube 链接。',\n errors: {\n coverMax: '最多可上传 {max} 张照片。',\n imageUrlRequired: '请输入图片地址。',\n imageUrlInvalid: '请输入有效的图片地址。',\n imageUrlHttps: '仅支持 HTTPS 图片地址。',\n imageUrlCredentials: '不能使用包含登录信息的地址。',\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: '请至少上传一张照片。',\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: '用于帖子和评论的实时数据库',\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: '用于网址和数据的标识',\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 autoTranslate: {\n action: \"翻译为10种语言\",\n manualHelp: \"一起翻译显示名称和说明,翻译后请点击保存以应用。\",\n pending: \"10种语言的翻译已就绪,请点击保存以应用。\",\n manualFailed: \"翻译失败,输入内容已保留,请重试。\",\n label: '保存时翻译成10种语言',\n help: '打开后,保存时会把名称和说明翻译成10种语言。关闭时不翻译。文字没变就不会再次翻译。',\n failed: '设置已保存,但翻译成10种语言失败了。请再次保存。',\n ready: '名称和说明已保存为10种语言。',\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 translateEmpty: '请先输入要翻译的标题或正文。',\n translateTooLong: '正文超过{limit}字时无法保存为10种语言。请缩短后再试。',\n translateIncomplete: '部分语言的翻译是空的。请重试。',\n failed: 'AI 处理失败,请重试。',\n actions: {\n proofread: '拼写检查',\n polish: '润色文字',\n continue: '自然续写',\n summarize: '简短总结',\n translateEn: '翻译成英语',\n translateKo: '翻译成韩语',\n translateAll: '翻译并保存为10种语言',\n translateSaved: '已保存为10种语言。用其他语言查看时会看到译文。',\n translatePending: '已准备好10种语言的翻译。保存文章时会一并记录。',\n translateEmpty: '请先输入要翻译的标题或正文。',\n title: '根据正文生成标题',\n custom: '改写为自定义风格…',\n },\n },\n}\n\nexport default messages\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memi-board",
3
- "version": "0.46.0",
3
+ "version": "0.46.2",
4
4
  "type": "module",
5
5
  "description": "Nuxt 4 + Nuxt UI + VueFire/Firebase 전용 게시판 모듈",
6
6
  "license": "MIT",
@@ -1 +0,0 @@
1
- {"version":3,"file":"ar-BCQdRw_S.js","names":[],"sources":["../src/i18n/messages/ar.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: 'يُرجى إدخال معرّف اللوحة واسمها.',\n deleteIdRequired: 'يلزم معرّف اللوحة لحذفها.',\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: 'موافق',\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: 'مساعد الكتابة بالذكاء الاصطناعي',\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: 'يُسمح فقط بعناوين URL للصور التي تبدأ بـ HTTPS.',\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: 'ارفع صورة واحدة على الأقل.',\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: 'الواجهة والتنسيق',\n backend: 'الخلفية والبيانات',\n },\n tech: {\n nuxt: 'إطار عمل SSR مبني على Vue',\n vue: 'Composition API · script setup',\n typescript: 'أنواع آمنة للبيانات والمكونات',\n nuxtUi: 'واجهة اللوحة والنماذج والنوافذ المنبثقة',\n tailwind: 'متجاوب · أنماط فاتحة/داكنة',\n lucide: 'أيقونات خفيفة ومتناسقة',\n dayjs: 'تواريخ وأوقات نسبية سهلة القراءة',\n firestore: 'قاعدة بيانات فورية للمنشورات والتعليقات',\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: 'املأ البيانات أدناه واحفظها لإنشائها بهذا المعرّف.',\n },\n noLabel: 'بلا تسمية',\n option: {\n default: 'قياسي',\n },\n id: {\n label: 'معرّف الفئة',\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: 'سجّل الدخول لاستخدام مساعد الكتابة بالذكاء الاصطناعي.',\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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"}