fix: 版本发布前国际化完善和代码质量修复
P0修复(阻塞发布): - 补充13个硬编码字符串的8种语言翻译 - 更新App Store评分链接为真实App ID (6756587477) - 移除URL强制解包,改用安全的可选绑定 P1修复(质量保证): - 本地化Info.plist权限说明(8种语言) - 统一developmentRegion为zh-Hans - 清理11处生产环境print语句,使用条件编译 P3修复(代码质量): - 清理4个冗余本地化key - 添加实用工具脚本(add_missing_strings.py, clean_redundant_keys.py) - 补充App Store元数据国际化文档 所有阻塞发布问题已修复,满足App Store审核要求。 Release构建验证通过(BUILD SUCCEEDED)。 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -193,7 +193,7 @@
|
||||
};
|
||||
};
|
||||
buildConfigurationList = F1A6CF4A2EED942500822C1B /* Build configuration list for PBXProject "to-live-photo" */;
|
||||
developmentRegion = en;
|
||||
developmentRegion = "zh-Hans";
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
@@ -203,9 +203,8 @@
|
||||
fr,
|
||||
ja,
|
||||
ko,
|
||||
zh-Hans,
|
||||
zh-Hant,
|
||||
|
||||
"zh-Hans",
|
||||
"zh-Hant",
|
||||
);
|
||||
mainGroup = F1A6CF462EED942500822C1B;
|
||||
minimizedProjectReferenceProxies = 1;
|
||||
@@ -420,8 +419,6 @@
|
||||
ENABLE_PREVIEWS = YES;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = "Live Photo Studio";
|
||||
INFOPLIST_KEY_NSPhotoLibraryAddUsageDescription = "用于将生成的 Live Photo 保存到系统相册";
|
||||
INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "用于读取并校验已保存的 Live Photo(可选)";
|
||||
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
|
||||
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
||||
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
||||
@@ -456,8 +453,6 @@
|
||||
ENABLE_PREVIEWS = YES;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = "Live Photo Studio";
|
||||
INFOPLIST_KEY_NSPhotoLibraryAddUsageDescription = "用于将生成的 Live Photo 保存到系统相册";
|
||||
INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "用于读取并校验已保存的 Live Photo(可选)";
|
||||
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
|
||||
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
||||
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
||||
|
||||
@@ -39,7 +39,9 @@ final class AppState {
|
||||
do {
|
||||
workflow = try LivePhotoWorkflow()
|
||||
} catch {
|
||||
#if DEBUG
|
||||
print("Failed to init LivePhotoWorkflow: \(error)")
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
112
to-live-photo/to-live-photo/InfoPlist.xcstrings
Normal file
112
to-live-photo/to-live-photo/InfoPlist.xcstrings
Normal file
@@ -0,0 +1,112 @@
|
||||
{
|
||||
"sourceLanguage": "zh-Hans",
|
||||
"strings": {
|
||||
"NSPhotoLibraryAddUsageDescription": {
|
||||
"extractionState": "manual",
|
||||
"localizations": {
|
||||
"zh-Hans": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "用于将生成的 Live Photo 保存到系统相册"
|
||||
}
|
||||
},
|
||||
"zh-Hant": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "用於將生成的 Live Photo 儲存至系統相簿"
|
||||
}
|
||||
},
|
||||
"en": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "To save generated Live Photos to your photo library"
|
||||
}
|
||||
},
|
||||
"es": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Para guardar Live Photos generadas en tu biblioteca de fotos"
|
||||
}
|
||||
},
|
||||
"ar": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "لحفظ Live Photos المُنشأة في مكتبة الصور"
|
||||
}
|
||||
},
|
||||
"fr": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Pour enregistrer les Live Photos générées dans votre bibliothèque de photos"
|
||||
}
|
||||
},
|
||||
"ja": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "生成したLive Photoをフォトライブラリに保存するために使用します"
|
||||
}
|
||||
},
|
||||
"ko": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "생성된 Live Photo를 사진 보관함에 저장하기 위해 사용됩니다"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"NSPhotoLibraryUsageDescription": {
|
||||
"extractionState": "manual",
|
||||
"localizations": {
|
||||
"zh-Hans": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "用于读取并校验已保存的 Live Photo(可选)"
|
||||
}
|
||||
},
|
||||
"zh-Hant": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "用於讀取並校驗已儲存的 Live Photo(選用)"
|
||||
}
|
||||
},
|
||||
"en": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "To read and verify saved Live Photos (optional)"
|
||||
}
|
||||
},
|
||||
"es": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Para leer y verificar Live Photos guardadas (opcional)"
|
||||
}
|
||||
},
|
||||
"ar": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "لقراءة والتحقق من Live Photos المحفوظة (اختياري)"
|
||||
}
|
||||
},
|
||||
"fr": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Pour lire et vérifier les Live Photos enregistrées (facultatif)"
|
||||
}
|
||||
},
|
||||
"ja": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "保存されたLive Photoを読み取り検証するために使用します(任意)"
|
||||
}
|
||||
},
|
||||
"ko": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "저장된 Live Photo를 읽고 확인하기 위해 사용됩니다(선택사항)"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"version": "1.0"
|
||||
}
|
||||
@@ -41,9 +41,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"%lld": {},
|
||||
"%lld%%": {},
|
||||
"•": {},
|
||||
"accessibility.aspectRatio": {
|
||||
"extractionState": "manual",
|
||||
"localizations": {
|
||||
@@ -97,7 +94,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"accessibility.aspectRatio %@": {},
|
||||
"accessibility.duration": {
|
||||
"extractionState": "manual",
|
||||
"localizations": {
|
||||
@@ -10002,6 +9998,695 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"processing.cancelling": {
|
||||
"extractionState": "manual",
|
||||
"localizations": {
|
||||
"zh-Hans": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "正在取消..."
|
||||
}
|
||||
},
|
||||
"zh-Hant": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "正在取消..."
|
||||
}
|
||||
},
|
||||
"en": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Cancelling..."
|
||||
}
|
||||
},
|
||||
"es": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Cancelando..."
|
||||
}
|
||||
},
|
||||
"ar": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "جارٍ الإلغاء..."
|
||||
}
|
||||
},
|
||||
"fr": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Annulation..."
|
||||
}
|
||||
},
|
||||
"ja": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "キャンセル中..."
|
||||
}
|
||||
},
|
||||
"ko": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "취소 중..."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"processing.failed": {
|
||||
"extractionState": "manual",
|
||||
"localizations": {
|
||||
"zh-Hans": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "生成失败"
|
||||
}
|
||||
},
|
||||
"zh-Hant": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "生成失敗"
|
||||
}
|
||||
},
|
||||
"en": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Generation Failed"
|
||||
}
|
||||
},
|
||||
"es": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Error al generar"
|
||||
}
|
||||
},
|
||||
"ar": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "فشل الإنشاء"
|
||||
}
|
||||
},
|
||||
"fr": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Échec de la génération"
|
||||
}
|
||||
},
|
||||
"ja": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "生成に失敗"
|
||||
}
|
||||
},
|
||||
"ko": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "생성 실패"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"processing.suggestions": {
|
||||
"extractionState": "manual",
|
||||
"localizations": {
|
||||
"zh-Hans": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "建议"
|
||||
}
|
||||
},
|
||||
"zh-Hant": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "建議"
|
||||
}
|
||||
},
|
||||
"en": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Suggestions"
|
||||
}
|
||||
},
|
||||
"es": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Sugerencias"
|
||||
}
|
||||
},
|
||||
"ar": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "اقتراحات"
|
||||
}
|
||||
},
|
||||
"fr": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Suggestions"
|
||||
}
|
||||
},
|
||||
"ja": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "提案"
|
||||
}
|
||||
},
|
||||
"ko": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "제안"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"editor.aspectRatioTitle": {
|
||||
"extractionState": "manual",
|
||||
"localizations": {
|
||||
"zh-Hans": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "画面比例"
|
||||
}
|
||||
},
|
||||
"zh-Hant": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "畫面比例"
|
||||
}
|
||||
},
|
||||
"en": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Aspect Ratio"
|
||||
}
|
||||
},
|
||||
"es": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Relación de aspecto"
|
||||
}
|
||||
},
|
||||
"ar": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "نسبة العرض"
|
||||
}
|
||||
},
|
||||
"fr": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Rapport d'aspect"
|
||||
}
|
||||
},
|
||||
"ja": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "アスペクト比"
|
||||
}
|
||||
},
|
||||
"ko": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "화면 비율"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"editor.aspectRatioHint": {
|
||||
"extractionState": "manual",
|
||||
"localizations": {
|
||||
"zh-Hans": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "选择适合壁纸的比例,锁屏推荐使用「锁屏」或「全屏」"
|
||||
}
|
||||
},
|
||||
"zh-Hant": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "選擇適合桌布的比例,鎖定畫面建議使用「鎖定畫面」或「全螢幕」"
|
||||
}
|
||||
},
|
||||
"en": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Choose a ratio suitable for wallpaper. 'Lock Screen' or 'Full Screen' is recommended"
|
||||
}
|
||||
},
|
||||
"es": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Elige una proporción adecuada. Se recomienda 'Pantalla de bloqueo' o 'Pantalla completa'"
|
||||
}
|
||||
},
|
||||
"ar": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "اختر نسبة مناسبة للخلفية. يُوصى بـ 'شاشة القفل' أو 'ملء الشاشة'"
|
||||
}
|
||||
},
|
||||
"fr": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Choisissez un ratio adapté. 'Écran verrouillé' ou 'Plein écran' est recommandé"
|
||||
}
|
||||
},
|
||||
"ja": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "壁紙に適した比率を選択してください。「ロック画面」または「全画面」を推奨"
|
||||
}
|
||||
},
|
||||
"ko": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "배경화면에 적합한 비율을 선택하세요. '잠금 화면' 또는 '전체 화면'을 권장합니다"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"editor.coverFrameTitle": {
|
||||
"extractionState": "manual",
|
||||
"localizations": {
|
||||
"zh-Hans": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "封面帧预览"
|
||||
}
|
||||
},
|
||||
"zh-Hant": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "封面影格預覽"
|
||||
}
|
||||
},
|
||||
"en": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Cover Frame Preview"
|
||||
}
|
||||
},
|
||||
"es": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Vista previa del cuadro de portada"
|
||||
}
|
||||
},
|
||||
"ar": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "معاينة الإطار الرئيسي"
|
||||
}
|
||||
},
|
||||
"fr": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Aperçu de l'image de couverture"
|
||||
}
|
||||
},
|
||||
"ja": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "カバーフレームのプレビュー"
|
||||
}
|
||||
},
|
||||
"ko": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "커버 프레임 미리보기"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"home.loadError": {
|
||||
"extractionState": "manual",
|
||||
"localizations": {
|
||||
"zh-Hans": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "加载失败: %@"
|
||||
}
|
||||
},
|
||||
"zh-Hant": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "載入失敗:%@"
|
||||
}
|
||||
},
|
||||
"en": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Loading failed: %@"
|
||||
}
|
||||
},
|
||||
"es": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Error de carga: %@"
|
||||
}
|
||||
},
|
||||
"ar": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "فشل التحميل: %@"
|
||||
}
|
||||
},
|
||||
"fr": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Échec du chargement : %@"
|
||||
}
|
||||
},
|
||||
"ja": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "読み込みに失敗しました:%@"
|
||||
}
|
||||
},
|
||||
"ko": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "로드 실패: %@"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"result.saved": {
|
||||
"extractionState": "manual",
|
||||
"localizations": {
|
||||
"zh-Hans": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Live Photo 已保存"
|
||||
}
|
||||
},
|
||||
"zh-Hant": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Live Photo 已儲存"
|
||||
}
|
||||
},
|
||||
"en": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Live Photo Saved"
|
||||
}
|
||||
},
|
||||
"es": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Live Photo guardada"
|
||||
}
|
||||
},
|
||||
"ar": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "تم حفظ Live Photo"
|
||||
}
|
||||
},
|
||||
"fr": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Live Photo enregistrée"
|
||||
}
|
||||
},
|
||||
"ja": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Live Photoを保存しました"
|
||||
}
|
||||
},
|
||||
"ko": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Live Photo가 저장되었습니다"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"result.saveFailed": {
|
||||
"extractionState": "manual",
|
||||
"localizations": {
|
||||
"zh-Hans": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "保存失败"
|
||||
}
|
||||
},
|
||||
"zh-Hant": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "儲存失敗"
|
||||
}
|
||||
},
|
||||
"en": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Save Failed"
|
||||
}
|
||||
},
|
||||
"es": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Error al guardar"
|
||||
}
|
||||
},
|
||||
"ar": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "فشل الحفظ"
|
||||
}
|
||||
},
|
||||
"fr": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Échec de l'enregistrement"
|
||||
}
|
||||
},
|
||||
"ja": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "保存に失敗"
|
||||
}
|
||||
},
|
||||
"ko": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "저장 실패"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"wallpaper.savedToLibrary": {
|
||||
"extractionState": "manual",
|
||||
"localizations": {
|
||||
"zh-Hans": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Live Photo 已保存到相册"
|
||||
}
|
||||
},
|
||||
"zh-Hant": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Live Photo 已儲存至相簿"
|
||||
}
|
||||
},
|
||||
"en": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Live Photo saved to library"
|
||||
}
|
||||
},
|
||||
"es": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Live Photo guardada en la biblioteca"
|
||||
}
|
||||
},
|
||||
"ar": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "تم حفظ Live Photo في المكتبة"
|
||||
}
|
||||
},
|
||||
"fr": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Live Photo enregistrée dans la bibliothèque"
|
||||
}
|
||||
},
|
||||
"ja": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Live Photoをライブラリに保存しました"
|
||||
}
|
||||
},
|
||||
"ko": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "라이브러리에 Live Photo가 저장되었습니다"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"wallpaper.deviceSupport": {
|
||||
"extractionState": "manual",
|
||||
"localizations": {
|
||||
"zh-Hans": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "你的设备支持锁屏动态壁纸"
|
||||
}
|
||||
},
|
||||
"zh-Hant": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "你的裝置支援鎖定畫面動態桌布"
|
||||
}
|
||||
},
|
||||
"en": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Your device supports lock screen live wallpaper"
|
||||
}
|
||||
},
|
||||
"es": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Tu dispositivo admite fondos animados en pantalla de bloqueo"
|
||||
}
|
||||
},
|
||||
"ar": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "جهازك يدعم خلفية شاشة القفل الحية"
|
||||
}
|
||||
},
|
||||
"fr": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Votre appareil prend en charge le fond d'écran animé sur l'écran verrouillé"
|
||||
}
|
||||
},
|
||||
"ja": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "お使いのデバイスはロック画面のライブ壁紙に対応しています"
|
||||
}
|
||||
},
|
||||
"ko": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "기기에서 잠금 화면 라이브 배경화면을 지원합니다"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"wallpaper.doneButton": {
|
||||
"extractionState": "manual",
|
||||
"localizations": {
|
||||
"zh-Hans": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "完成,返回首页"
|
||||
}
|
||||
},
|
||||
"zh-Hant": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "完成,返回首頁"
|
||||
}
|
||||
},
|
||||
"en": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Done, Return to Home"
|
||||
}
|
||||
},
|
||||
"es": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Listo, volver al inicio"
|
||||
}
|
||||
},
|
||||
"ar": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "تم، العودة إلى الصفحة الرئيسية"
|
||||
}
|
||||
},
|
||||
"fr": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Terminé, retour à l'accueil"
|
||||
}
|
||||
},
|
||||
"ja": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "完了、ホームに戻る"
|
||||
}
|
||||
},
|
||||
"ko": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "완료, 홈으로 돌아가기"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"wallpaper.canAlwaysCreate": {
|
||||
"extractionState": "manual",
|
||||
"localizations": {
|
||||
"zh-Hans": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "你可以随时制作新的 Live Photo"
|
||||
}
|
||||
},
|
||||
"zh-Hant": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "你可以隨時製作新的 Live Photo"
|
||||
}
|
||||
},
|
||||
"en": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "You can create new Live Photos anytime"
|
||||
}
|
||||
},
|
||||
"es": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Puedes crear nuevas Live Photos en cualquier momento"
|
||||
}
|
||||
},
|
||||
"ar": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "يمكنك إنشاء Live Photos جديدة في أي وقت"
|
||||
}
|
||||
},
|
||||
"fr": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Vous pouvez créer de nouvelles Live Photos à tout moment"
|
||||
}
|
||||
},
|
||||
"ja": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "いつでも新しいLive Photoを作成できます"
|
||||
}
|
||||
},
|
||||
"ko": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "언제든지 새로운 Live Photo를 만들 수 있습니다"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"version": "1.0"
|
||||
|
||||
@@ -109,7 +109,9 @@ final class RecentWorksManager: ObservableObject {
|
||||
do {
|
||||
recentWorks = try JSONDecoder().decode([RecentWork].self, from: data)
|
||||
} catch {
|
||||
#if DEBUG
|
||||
print("[RecentWorksManager] Failed to decode: \(error)")
|
||||
#endif
|
||||
recentWorks = []
|
||||
}
|
||||
}
|
||||
@@ -119,7 +121,9 @@ final class RecentWorksManager: ObservableObject {
|
||||
let data = try JSONEncoder().encode(recentWorks)
|
||||
UserDefaults.standard.set(data, forKey: userDefaultsKey)
|
||||
} catch {
|
||||
#if DEBUG
|
||||
print("[RecentWorksManager] Failed to encode: \(error)")
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,7 +219,7 @@ struct EditorView: View {
|
||||
HStack {
|
||||
Image(systemName: "aspectratio")
|
||||
.foregroundStyle(.tint)
|
||||
Text("画面比例")
|
||||
Text(String(localized: "editor.aspectRatioTitle"))
|
||||
.font(.headline)
|
||||
}
|
||||
|
||||
@@ -237,7 +237,7 @@ struct EditorView: View {
|
||||
}
|
||||
}
|
||||
|
||||
Text("选择适合壁纸的比例,锁屏推荐使用「锁屏」或「全屏」")
|
||||
Text(String(localized: "editor.aspectRatioHint"))
|
||||
.font(.caption)
|
||||
.foregroundColor(.textSecondary)
|
||||
}
|
||||
@@ -253,7 +253,7 @@ struct EditorView: View {
|
||||
HStack {
|
||||
Image(systemName: "photo")
|
||||
.foregroundStyle(.tint)
|
||||
Text("封面帧预览")
|
||||
Text(String(localized: "editor.coverFrameTitle"))
|
||||
.font(.headline)
|
||||
Spacer()
|
||||
if isLoadingCover {
|
||||
@@ -651,7 +651,9 @@ struct EditorView: View {
|
||||
extractCoverFrame()
|
||||
}
|
||||
} catch {
|
||||
#if DEBUG
|
||||
print("Failed to load video duration: \(error)")
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -684,7 +686,9 @@ struct EditorView: View {
|
||||
await MainActor.run {
|
||||
isLoadingCover = false
|
||||
}
|
||||
#if DEBUG
|
||||
print("Failed to extract cover frame: \(error)")
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -757,7 +761,9 @@ struct EditorView: View {
|
||||
// 下载失败时禁用 AI 增强
|
||||
aiEnhanceEnabled = false
|
||||
}
|
||||
#if DEBUG
|
||||
print("Failed to download AI model: \(error)")
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -233,7 +233,7 @@ struct HomeView: View {
|
||||
Analytics.shared.log(.importVideoSuccess)
|
||||
appState.navigateTo(.editor(videoURL: movie.url))
|
||||
} catch {
|
||||
errorMessage = "加载失败: \(error.localizedDescription)"
|
||||
errorMessage = String(localized: "home.loadError \(error.localizedDescription)")
|
||||
isLoading = false
|
||||
Analytics.shared.logError(.importVideoFail, error: error)
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ struct ProcessingView: View {
|
||||
.tint(.textMuted)
|
||||
}
|
||||
|
||||
Text("正在取消...")
|
||||
Text(String(localized: "processing.cancelling"))
|
||||
.font(.system(size: DesignTokens.FontSize.lg, weight: .semibold))
|
||||
.foregroundColor(.textSecondary)
|
||||
}
|
||||
@@ -161,7 +161,7 @@ struct ProcessingView: View {
|
||||
// 错误信息
|
||||
if let error = appState.processingError {
|
||||
VStack(spacing: DesignTokens.Spacing.md) {
|
||||
Text("生成失败")
|
||||
Text(String(localized: "processing.failed"))
|
||||
.font(.system(size: DesignTokens.FontSize.xl, weight: .bold))
|
||||
.foregroundColor(.textPrimary)
|
||||
|
||||
@@ -176,7 +176,7 @@ struct ProcessingView: View {
|
||||
HStack {
|
||||
Image(systemName: "lightbulb.fill")
|
||||
.foregroundColor(.accentOrange)
|
||||
Text("建议")
|
||||
Text(String(localized: "processing.suggestions"))
|
||||
.font(.system(size: DesignTokens.FontSize.sm, weight: .semibold))
|
||||
.foregroundColor(.textPrimary)
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ struct ResultView: View {
|
||||
@ViewBuilder
|
||||
private var resultInfo: some View {
|
||||
VStack(spacing: DesignTokens.Spacing.lg) {
|
||||
Text(isSuccess ? "Live Photo 已保存" : "保存失败")
|
||||
Text(isSuccess ? String(localized: "result.saved") : String(localized: "result.saveFailed"))
|
||||
.font(.system(size: DesignTokens.FontSize.xxl, weight: .bold))
|
||||
.foregroundColor(.textPrimary)
|
||||
|
||||
|
||||
@@ -98,13 +98,16 @@ struct SettingsView: View {
|
||||
Label(String(localized: "settings.exportDiagnostics"), systemImage: "doc.text")
|
||||
}
|
||||
|
||||
Link(destination: URL(string: "mailto:support@let5see.xyz")!) {
|
||||
Label(String(localized: "settings.contactUs"), systemImage: "envelope")
|
||||
if let mailURL = URL(string: "mailto:let5sne@gmail.com") {
|
||||
Link(destination: mailURL) {
|
||||
Label(String(localized: "settings.contactUs"), systemImage: "envelope")
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: App Store 上架后替换为实际的 App ID
|
||||
Link(destination: URL(string: "https://apps.apple.com/app/id000000000")!) {
|
||||
Label(String(localized: "settings.rateApp"), systemImage: "star")
|
||||
if let appStoreURL = URL(string: "https://apps.apple.com/app/id6756587477") {
|
||||
Link(destination: appStoreURL) {
|
||||
Label(String(localized: "settings.rateApp"), systemImage: "star")
|
||||
}
|
||||
}
|
||||
} header: {
|
||||
Text(String(localized: "settings.feedback"))
|
||||
@@ -393,7 +396,9 @@ struct SettingsView: View {
|
||||
return fallbackURL
|
||||
|
||||
} catch {
|
||||
#if DEBUG
|
||||
print("[SettingsView] Failed to create feedback package: \(error)")
|
||||
#endif
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ struct WallpaperGuideView: View {
|
||||
.foregroundStyle(.tint)
|
||||
.padding(.bottom, 4)
|
||||
|
||||
Text("Live Photo 已保存到相册")
|
||||
Text(String(localized: "wallpaper.savedToLibrary"))
|
||||
.font(.title3)
|
||||
.fontWeight(.bold)
|
||||
|
||||
@@ -55,7 +55,7 @@ struct WallpaperGuideView: View {
|
||||
HStack(spacing: 6) {
|
||||
Image(systemName: "checkmark.circle.fill")
|
||||
.foregroundStyle(.green)
|
||||
Text("你的设备支持锁屏动态壁纸")
|
||||
Text(String(localized: "wallpaper.deviceSupport"))
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
.font(.subheadline)
|
||||
@@ -227,7 +227,7 @@ struct WallpaperGuideView: View {
|
||||
Analytics.shared.log(.guideComplete)
|
||||
appState.popToRoot()
|
||||
} label: {
|
||||
Text("完成,返回首页")
|
||||
Text(String(localized: "wallpaper.doneButton"))
|
||||
.font(.headline)
|
||||
.frame(maxWidth: .infinity)
|
||||
.padding()
|
||||
@@ -236,7 +236,7 @@ struct WallpaperGuideView: View {
|
||||
.clipShape(RoundedRectangle(cornerRadius: 14))
|
||||
}
|
||||
|
||||
Text("你可以随时制作新的 Live Photo")
|
||||
Text(String(localized: "wallpaper.canAlwaysCreate"))
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user