feat(i18n): T15 full-stack language audit with coverage assertions
- viewer/admin 错误码→文案映射按契约 ErrorCodes 枚举全集登记(机器守护 spec 遍历枚举断言无缺漏 + 映射键在 zh/en 词条均存在 + locale 键集 递归相等);mobile 镜像补齐 DOWNLOAD_DISABLED(P4a 增补漏登) - 漏译修复:viewer.photoRemoved en 侧缺失(审计测试捕获); DOWNLOAD_DISABLED 观众侧专属文案 + useDownload 专属提示接线; admin apiMsg 增 RATE_LIMITED/ALBUM_NOT_PUBLIC/DOWNLOAD_DISABLED/ SYNC_AUTH_FAILED 四码词条 - 运行时抽查:admin 主旅程 en 版 e2e(登录→相册管理全英文 + 偏好 持久);embed iframe lang=en 渲染与深链跟随 e2e(zh 侧既有用例覆盖) - contracts 新增 ./errors 浏览器安全子路径(errors.ts 纯 TS); admin 增 @photo/contracts devDep(仅测试消费) Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -17,10 +17,12 @@
|
||||
// 打开后可正常下载)。clipboard 不可用时降级展示可选中文本供手动长按复制。
|
||||
import { computed, onBeforeUnmount, reactive, ref, type Ref } from 'vue';
|
||||
import {
|
||||
ApiError,
|
||||
getPhotoDownload,
|
||||
type DownloadVariant,
|
||||
type PublicAlbum,
|
||||
} from '../api/client';
|
||||
import { ErrorCodes } from '@photo/contracts/errors';
|
||||
|
||||
export interface DownloadInputs {
|
||||
token: Ref<string>;
|
||||
@@ -63,7 +65,9 @@ export const COPY_NOTICE_MS = 2500;
|
||||
|
||||
export function useDownload(inputs: DownloadInputs) {
|
||||
const busy = ref(false);
|
||||
const failed = ref(false);
|
||||
/** 失败文案键(''=无失败):默认通用失败;DOWNLOAD_DISABLED 给专属文案
|
||||
* (T15 漏译修复——相册中途关闭下载开关时观众可理解的确定性提示)。 */
|
||||
const failed = ref<'' | 'download.failed' | 'errors.downloadDisabled'>('');
|
||||
/** 微信引导浮层可见(点击下载时处于微信内置浏览器)。 */
|
||||
const wechatGuide = ref(false);
|
||||
const copyNotice = ref<'' | 'copied' | 'failed'>('');
|
||||
@@ -90,7 +94,7 @@ export function useDownload(inputs: DownloadInputs) {
|
||||
const photoId = inputs.photoId();
|
||||
if (photoId === null || busy.value) return;
|
||||
busy.value = true;
|
||||
failed.value = false;
|
||||
failed.value = '';
|
||||
try {
|
||||
let credential = await getPhotoDownload(inputs.token.value, photoId, variant);
|
||||
if (isExpired(credential.expiresAt)) {
|
||||
@@ -99,8 +103,11 @@ export function useDownload(inputs: DownloadInputs) {
|
||||
credential = await getPhotoDownload(inputs.token.value, photoId, variant);
|
||||
}
|
||||
openDownloadUrl(credential.url);
|
||||
} catch {
|
||||
failed.value = true;
|
||||
} catch (error) {
|
||||
failed.value =
|
||||
error instanceof ApiError && error.code === ErrorCodes.DOWNLOAD_DISABLED
|
||||
? 'errors.downloadDisabled'
|
||||
: 'download.failed';
|
||||
} finally {
|
||||
busy.value = false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user