trypost/lang/ko/assets.php

55 lines
1.9 KiB
PHP
Raw Permalink Normal View History

<?php
return [
'title' => '에셋',
'tabs' => [
'my_uploads' => '내 업로드',
'stock_photos' => '스톡 사진',
'gifs' => 'GIF',
],
'upload' => [
'drag_drop' => '여기에 파일을 끌어다 놓거나 클릭하여 선택하세요',
'formats' => 'JPEG, PNG, GIF, WebP, MP4, PDF',
'uploading' => '업로드 중...',
'failed' => ':file을(를) 업로드할 수 없습니다. 다시 시도해 주세요.',
fix: chunked upload session collision + workspace name i18n (#263) * fix: give each chunked upload attempt a unique server-side identifier The upload session identifier was derived only from user+filename+size (ChunkedAssetReceiver::receive), with no per-attempt nonce. Two genuinely concurrent attempts of the same file (e.g. closing and reopening the media picker mid-upload, then re-uploading the same file) collided on the same Redis cache key / temp file, producing RuntimeException("Chunked cloud upload session expired or missing.") on the multipart/cloud path and silent byte corruption on the local-assemble path. The frontend now mints a UUID per upload attempt (X-Upload-Id header) that gets folded into the identifier. Falls back to the old formula when the header is absent, so any already-loaded frontend bundle keeps working. Also guards the media picker's dropzone against re-triggering an upload while one is in flight, and aborts the in-flight fetch when the dialog unmounts mid-upload. Fixes Nightwatch issue #23. * fix: explicitly type upload_id when passing to receive() Matches the existing explicit (int) casts on the sibling validated() calls in the same method — validated() returns mixed, so this keeps the nullable-string contract explicit instead of relying on an implicit runtime type. * style: inline the upload_id null-safe cast Drop the intermediate variable so all receive() arguments read as a single expression each, matching the sibling validated() casts. * fix: require X-Upload-Id instead of falling back to the legacy identifier Nullable upload_id only preserved the old (collision-prone) formula for clients that omit the header — it didn't actually protect them. Making it required closes that gap outright: a request without the header now fails loud (422) instead of silently falling back to the vulnerable identifier. ChunkedAssetReceiver::receive() now takes a required $attemptId. Updated every existing test hitting app.assets.store-chunked (ChunkedCloudUploadTest, ChunkedAssetReceiverTest, ChunkedUploadFilenameEncodingTest, AssetControllerTest) to send a real upload id, and added a regression test asserting the endpoint rejects a request with no X-Upload-Id header. * fix: localize hardcoded workspace name validation messages StoreWorkspaceRequest had its custom messages() hardcoded in pt-BR regardless of the user's locale; UpdateWorkspaceRequest had the same bug hardcoded in English. Both now go through __('validation.required' / 'validation.max.string') with the already-localized workspaces.create.name attribute label (present in all 16 lang/ directories), matching the pattern already used by StoreWorkspaceInviteRequest. Unrelated to the chunked upload fix, but caught while reviewing this file's messages() convention. * simplify: drop messages() override on workspace name validation Laravel already localizes the generic required/max messages from lang/{locale}/validation.php automatically — no need to hand-roll messages() for standard rules with no custom copy. * fix: localize StoreChunkedAssetRequest validation messages Drop the hardcoded English messages for required/ends_with rules — Laravel's own localized validation.php messages already cover them adequately (ends_with's generic message is actually more useful, since it lists the accepted extensions). total_size.max still needs a custom message (the rule is in raw bytes, unreadable without MB conversion), so it now goes through __('assets.upload.file_too_large') with the key added to all 16 lang/ locales. Also fixed test flakiness discovered while touching this file: ChunkedCloudUploadTest used random_bytes() for the first mp4 chunk, which occasionally collides with an unrelated magic number (MZ/PE, SIMH tape, ...) and makes finfo misdetect the mime type. Replaced with real mp4 header bytes padded with nulls, so detection is deterministic. * fix: address final code review findings - ChunkedAssetReceiver: use double-quoted interpolation instead of concatenation for the identifier hash, per project convention. - AssetControllerTest: two chunked-upload rejection tests didn't send X-Upload-Id, so their 422 assertions could pass for the wrong reason (upload_id.required) instead of the field they claim to cover. Added the header and asserted the specific validation error field. - GalleryBrowser: centralize the upload-in-progress guard as a single check at the top of uploadFiles() instead of three separate checks at each entry point (click/select/drop) — matches the single-source- of-truth pattern already used in PhotoUpload.vue. - GalleryBrowser: show a toast when an in-flight upload is aborted (dialog closed mid-upload) instead of silently discarding it with no feedback. New assets.upload.cancelled key added to all 16 lang/ locales.
2026-08-09 17:06:47 +00:00
'file_too_large' => '파일 크기가 허용된 최대값(:max MB)을 초과했습니다.',
'cancelled' => '업로드가 취소되었습니다.',
],
'empty' => [
'title' => '아직 에셋이 없습니다',
'description' => '이미지와 동영상을 업로드하여 미디어 라이브러리를 만드세요.',
],
'save_to_assets' => '에셋에 저장',
'saved' => '에셋에 저장되었습니다!',
'create_post' => '게시물 만들기',
'add_to_post' => '게시물에 추가',
'search_placeholder' => '미디어 검색...',
'delete' => [
'title' => '에셋 삭제',
'description' => '이 에셋을 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다.',
'confirm' => '삭제',
'cancel' => '취소',
],
'unsplash' => [
'search_placeholder' => '무료 사진 검색...',
'no_results' => '사진을 찾을 수 없습니다',
'no_results_description' => '다른 검색어로 시도해 보세요.',
'trending' => 'Unsplash 인기 사진',
'start_searching' => 'Unsplash의 무료 스톡 사진을 검색하세요',
],
'giphy' => [
'trending' => 'Giphy 인기 GIF',
'search_placeholder' => 'GIF 검색...',
'no_results' => 'GIF를 찾을 수 없습니다',
'no_results_description' => '다른 검색어로 시도해 보세요.',
'powered_by' => 'Powered by GIPHY',
],
];