diff --git a/LiveContainerSwiftUI/Assets.xcassets/GitHub.imageset/Contents.json b/LiveContainerSwiftUI/Assets.xcassets/GitHub.imageset/Contents.json new file mode 100644 index 0000000..79ee99e --- /dev/null +++ b/LiveContainerSwiftUI/Assets.xcassets/GitHub.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "GitHub@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "GitHub@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Resources/GitHub@2x.png b/LiveContainerSwiftUI/Assets.xcassets/GitHub.imageset/GitHub@2x.png similarity index 100% rename from Resources/GitHub@2x.png rename to LiveContainerSwiftUI/Assets.xcassets/GitHub.imageset/GitHub@2x.png diff --git a/Resources/GitHub@3x.png b/LiveContainerSwiftUI/Assets.xcassets/GitHub.imageset/GitHub@3x.png similarity index 100% rename from Resources/GitHub@3x.png rename to LiveContainerSwiftUI/Assets.xcassets/GitHub.imageset/GitHub@3x.png diff --git a/LiveContainerSwiftUI/Assets.xcassets/Twitter.imageset/Contents.json b/LiveContainerSwiftUI/Assets.xcassets/Twitter.imageset/Contents.json new file mode 100644 index 0000000..65a02fa --- /dev/null +++ b/LiveContainerSwiftUI/Assets.xcassets/Twitter.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Twitter@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Twitter@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Resources/Twitter@2x.png b/LiveContainerSwiftUI/Assets.xcassets/Twitter.imageset/Twitter@2x.png similarity index 100% rename from Resources/Twitter@2x.png rename to LiveContainerSwiftUI/Assets.xcassets/Twitter.imageset/Twitter@2x.png diff --git a/Resources/Twitter@3x.png b/LiveContainerSwiftUI/Assets.xcassets/Twitter.imageset/Twitter@3x.png similarity index 100% rename from Resources/Twitter@3x.png rename to LiveContainerSwiftUI/Assets.xcassets/Twitter.imageset/Twitter@3x.png diff --git a/LiveContainerSwiftUI/LCAppBanner.swift b/LiveContainerSwiftUI/LCAppBanner.swift index 3eecab6..3705a43 100644 --- a/LiveContainerSwiftUI/LCAppBanner.swift +++ b/LiveContainerSwiftUI/LCAppBanner.swift @@ -73,7 +73,7 @@ struct LCAppBanner : View, LCAppSettingDelegate { HStack { Text(appInfo.displayName()).font(.system(size: 16)).bold() if model.uiIsShared { - Text("SHARED").font(.system(size: 8)).bold().padding(2) + Text("lc.appBanner.shared".loc).font(.system(size: 8)).bold().padding(2) .frame(width: 50, height:16) .background( Capsule().fill(Color("BadgeColor")) @@ -89,7 +89,7 @@ struct LCAppBanner : View, LCAppSettingDelegate { } Text("\(appInfo.version()) - \(appInfo.bundleIdentifier())").font(.system(size: 12)).foregroundColor(Color("FontColor")) - Text(model.uiDataFolder == nil ? "Data folder not created yet" : model.uiDataFolder!).font(.system(size: 8)).foregroundColor(Color("FontColor")) + Text(LocalizedStringKey(model.uiDataFolder == nil ? "lc.appBanner.noDataFolder".loc : model.uiDataFolder!)).font(.system(size: 8)).foregroundColor(Color("FontColor")) }) } Spacer() @@ -97,7 +97,7 @@ struct LCAppBanner : View, LCAppSettingDelegate { Task{ await runApp() } } label: { if !isSingingInProgress { - Text("Run").bold().foregroundColor(.white) + Text("lc.appBanner.run".loc).bold().foregroundColor(.white) } else { ProgressView().progressViewStyle(.circular) } @@ -150,7 +150,7 @@ struct LCAppBanner : View, LCAppSettingDelegate { Button { openDataFolder() } label: { - Label("Open Data Folder", systemImage: "folder") + Label("lc.appBanner.openDataFolder".loc, systemImage: "folder") } } } @@ -159,28 +159,28 @@ struct LCAppBanner : View, LCAppSettingDelegate { Button { openSafariViewToCreateAppClip() } label: { - Label("Create App Clip", systemImage: "appclip") + Label("lc.appBanner.createAppClip".loc, systemImage: "appclip") } Button { copyLaunchUrl() } label: { - Label("Copy Launch Url", systemImage: "link") + Label("lc.appBanner.copyLaunchUrl".loc, systemImage: "link") } Button { saveIcon() } label: { - Label("Save App Icon", systemImage: "square.and.arrow.down") + Label("lc.appBanner.saveAppIcon".loc, systemImage: "square.and.arrow.down") } } label: { - Label("Add to Home Screen", systemImage: "plus.app") + Label("lc.appBanner.addToHomeScreen".loc, systemImage: "plus.app") } Button { openSettings() } label: { - Label("Settings", systemImage: "gear") + Label("lc.tabView.settings".loc, systemImage: "gear") } @@ -188,7 +188,7 @@ struct LCAppBanner : View, LCAppSettingDelegate { Button(role: .destructive) { Task{ await uninstall() } } label: { - Label("Uninstall", systemImage: "trash") + Label("lc.appBanner.uninstall".loc, systemImage: "trash") } } @@ -208,51 +208,51 @@ struct LCAppBanner : View, LCAppSettingDelegate { Task { await handleURLSchemeLaunch() } } - .alert("Confirm Uninstallation", isPresented: $confirmAppRemovalShow) { + .alert("lc.appBanner.confirmUninstallTitle".loc, isPresented: $confirmAppRemovalShow) { Button(role: .destructive) { self.confirmAppRemoval = true self.appRemovalContinuation?.resume() } label: { - Text("Uninstall") + Text("lc.appBanner.uninstall".loc) } - Button("Cancel", role: .cancel) { + Button("lc.common.cancel".loc, role: .cancel) { self.confirmAppRemoval = false self.appRemovalContinuation?.resume() } } message: { - Text("Are you sure you want to uninstall \(appInfo.displayName()!)?") + Text("lc.appBanner.confirmUninstallMsg %@".localizeWithFormat(appInfo.displayName()!)) } - .alert("Delete Data Folder", isPresented: $confirmAppFolderRemovalShow) { + .alert("lc.appBanner.deleteDataTitle".loc, isPresented: $confirmAppFolderRemovalShow) { Button(role: .destructive) { self.confirmAppFolderRemoval = true self.appFolderRemovalContinuation?.resume() } label: { - Text("Delete") + Text("lc.common.delete".loc) } - Button("Cancel", role: .cancel) { + Button("lc.common.cancel".loc, role: .cancel) { self.confirmAppFolderRemoval = false self.appFolderRemovalContinuation?.resume() } } message: { - Text("Do you also want to delete data folder of \(appInfo.displayName()!)? You can keep it for future use.") + Text("lc.appBanner.deleteDataMsg \(appInfo.displayName()!)") } - .alert("Waiting for JIT", isPresented: $enablingJITShow) { + .alert("lc.appBanner.waitForJitTitle".loc, isPresented: $enablingJITShow) { Button { self.confirmEnablingJIT = true self.confirmEnablingJITContinuation?.resume() } label: { - Text("Launch Now") + Text("lc.appBanner.jitLaunchNow".loc) } - Button("Cancel", role: .cancel) { + Button("lc.common.cancel", role: .cancel) { self.confirmEnablingJIT = false self.confirmEnablingJITContinuation?.resume() } } message: { - Text("Please use your favourite way to enable jit for current LiveContainer.") + Text("lc.appBanner.waitForJitMsg".loc) } - .alert("Error", isPresented: $errorShow) { - Button("OK", action: { + .alert("lc.common.error".loc, isPresented: $errorShow) { + Button("lc.common.ok".loc, action: { }) } message: { Text(errorInfo) diff --git a/LiveContainerSwiftUI/LCAppListView.swift b/LiveContainerSwiftUI/LCAppListView.swift index 1956f36..8d9955c 100644 --- a/LiveContainerSwiftUI/LCAppListView.swift +++ b/LiveContainerSwiftUI/LCAppListView.swift @@ -99,7 +99,7 @@ struct LCAppListView : View, LCAppBannerDelegate { .animation(.easeInOut, value: apps) if !sharedModel.isHiddenAppUnlocked { - Text(apps.count > 0 ? "\(apps.count) Apps in Total" : "Press the Plus Button to Install Apps.").foregroundStyle(.gray) + Text(apps.count > 0 ? "lc.appList.appCounter %lld".localizeWithFormat(apps.count) : "lc.appList.installTip".loc).foregroundStyle(.gray) .onTapGesture(count: 3) { Task { await authenticateUser() } } @@ -109,7 +109,7 @@ struct LCAppListView : View, LCAppBannerDelegate { if sharedModel.isHiddenAppUnlocked { LazyVStack { HStack { - Text("Hidden Apps") + Text("lc.appList.hiddenApps".loc) .font(.system(.title2).bold()) .border(Color.black) Spacer() @@ -123,14 +123,14 @@ struct LCAppListView : View, LCAppBannerDelegate { .animation(.easeInOut, value: apps) if hiddenApps.count == 0 { - Text("Long Press on a App to Make it Hidden.") + Text("lc.appList.hideAppTip".loc) .foregroundStyle(.gray) } - Text(apps.count + hiddenApps.count > 0 ? "\(apps.count + hiddenApps.count) Apps in Total" : "Press the Plus Button to Install Apps.").foregroundStyle(.gray) + Text(apps.count + hiddenApps.count > 0 ? "lc.appList.appCounter %lld".localizeWithFormat(apps.count + hiddenApps.count) : "lc.appList.installTip".loc).foregroundStyle(.gray) } if LCUtils.multiLCStatus == 2 { - Text("Manage apps in the primary LiveContainer").foregroundStyle(.gray).padding() + Text("lc.appList.manageInPrimaryTip".loc).foregroundStyle(.gray).padding() } } @@ -146,12 +146,12 @@ struct LCAppListView : View, LCAppBannerDelegate { onLaunchBundleIdChange() } - .navigationTitle("My Apps") + .navigationTitle("lc.appList.myApps".loc) .toolbar { ToolbarItem(placement: .topBarLeading) { if LCUtils.multiLCStatus != 2 { if !installprogressVisible { - Button("Add", systemImage: "plus", action: { + Button("Add".loc, systemImage: "plus", action: { if choosingIPA { choosingIPA = false DispatchQueue.main.asyncAfter(deadline: .now() + 0.1, execute: { @@ -169,7 +169,7 @@ struct LCAppListView : View, LCAppBannerDelegate { } } ToolbarItem(placement: .topBarTrailing) { - Button("Open Link", systemImage: "link", action: { + Button("lc.appList.openLink".loc, systemImage: "link", action: { Task { await onOpenWebViewTapped() } }) } @@ -179,18 +179,18 @@ struct LCAppListView : View, LCAppBannerDelegate { } .navigationViewStyle(StackNavigationViewStyle()) .alert(isPresented: $errorShow){ - Alert(title: Text("Error"), message: Text(errorInfo)) + Alert(title: Text("lc.common.error".loc), message: Text(errorInfo)) } .fileImporter(isPresented: $choosingIPA, allowedContentTypes: [.ipa]) { result in Task { await startInstallApp(result) } } - .alert("Installation", isPresented: $installReplaceComfirmVisible) { + .alert("lc.appList.installation".loc, isPresented: $installReplaceComfirmVisible) { ForEach(installOptions, id: \.self) { installOption in Button(role: installOption.isReplace ? .destructive : nil, action: { self.installOptionChosen = installOption self.installOptionContinuation?.resume() }, label: { - Text(installOption.isReplace ? installOption.nameOfFolderToInstall : "Install as new") + Text(installOption.isReplace ? installOption.nameOfFolderToInstall : "lc.appList.installAsNew".loc) }) } @@ -198,14 +198,14 @@ struct LCAppListView : View, LCAppBannerDelegate { self.installOptionChosen = nil self.installOptionContinuation?.resume() }, label: { - Text("Abort Installation") + Text("lc.appList.abortInstallation".loc) }) } message: { - Text("There is an existing application with the same bundle identifier. Replace one or install as new.") + Text("lc.appList.installReplaceTip".loc) } .textFieldAlert( isPresented: $webViewUrlInputOpened, - title: "Enter Url or Url Scheme", + title: "lc.appList.enterUrlTip".loc, text: $webViewUrlInputContent, placeholder: "scheme://", action: { newText in @@ -252,7 +252,7 @@ struct LCAppListView : View, LCAppBannerDelegate { func openWebView(urlString: String) async { guard var urlToOpen = URLComponents(string: urlString), urlToOpen.url != nil else { - errorInfo = "The input url is invalid. Please check and try again" + errorInfo = "lc.appList.urlInvalidError".loc errorShow = true webViewUrlInputContent = "" return @@ -283,7 +283,7 @@ struct LCAppListView : View, LCAppBannerDelegate { guard let appToLaunch = appToLaunch else { - errorInfo = "Scheme \"\(urlToOpen.scheme!)\" cannot be opened by any app installed in LiveContainer." + errorInfo = "lc.appList.schemeCannotOpenError %@".localizeWithFormat(urlToOpen.scheme!) errorShow = true return } @@ -337,7 +337,7 @@ struct LCAppListView : View, LCAppBannerDelegate { func installIpaFile(_ url:URL) async throws { if(!url.startAccessingSecurityScopedResource()) { - throw "Failed to access IPA"; + throw "lc.appList.ipaAccessError".loc; } let fm = FileManager() @@ -368,13 +368,13 @@ struct LCAppListView : View, LCAppBannerDelegate { } } guard let appBundleName = appBundleName else { - throw "App bundle not found" + throw "lc.appList.bundleNotFondError".loc } let appFolderPath = payloadPath.appendingPathComponent(appBundleName) guard let newAppInfo = LCAppInfo(bundlePath: appFolderPath.path) else { - throw "Failed to read app's Info.plist." + throw "lc.appList.infoPlistCannotReadError".loc } var appRelativePath = "\(newAppInfo.bundleIdentifier()!).app" @@ -422,7 +422,7 @@ struct LCAppListView : View, LCAppBannerDelegate { // patch it guard let finalNewApp else { - errorInfo = "Failed to Initialize AppInfo!" + errorInfo = "lc.appList.appInfoInitError".loc errorShow = true return } @@ -513,7 +513,7 @@ struct LCAppListView : View, LCAppBannerDelegate { } if !appFound { - errorInfo = "App not Found" + errorInfo = "lc.appList.appNotFoundError".loc errorShow = true } } diff --git a/LiveContainerSwiftUI/LCAppSettingsView.swift b/LiveContainerSwiftUI/LCAppSettingsView.swift index 033dd22..a103d84 100644 --- a/LiveContainerSwiftUI/LCAppSettingsView.swift +++ b/LiveContainerSwiftUI/LCAppSettingsView.swift @@ -85,7 +85,7 @@ struct LCAppSettingsView : View{ Form { Section { HStack { - Text("Bundle Identifier") + Text("lc.appSettings.bundleId".loc) Spacer() Text(appInfo.relativeBundlePath) .foregroundColor(.gray) @@ -96,13 +96,13 @@ struct LCAppSettingsView : View{ Button { Task{ await createFolder() } } label: { - Label("New data folder", systemImage: "plus") + Label("lc.appSettings.newDataFolder".loc, systemImage: "plus") } if model.uiDataFolder != nil { Button { Task{ await renameDataFolder() } } label: { - Label("Rename data folder", systemImage: "pencil") + Label("lc.appSettings.renameDataFolder".loc, systemImage: "pencil") } } @@ -115,10 +115,10 @@ struct LCAppSettingsView : View{ } } label: { HStack { - Text("Data Folder") + Text("lc.appSettings.dataFolder".loc) .foregroundColor(.primary) Spacer() - Text(model.uiDataFolder == nil ? "Not created yet" : model.uiDataFolder!) + Text(model.uiDataFolder == nil ? "lc.appSettings.noDataFolder".loc : model.uiDataFolder!) .multilineTextAlignment(.trailing) } } @@ -130,14 +130,14 @@ struct LCAppSettingsView : View{ Menu { Picker(selection: $uiPickerTweakFolder , label: Text("")) { - Label("None", systemImage: "nosign").tag(Optional(nil)) + Label("lc.common.none".loc, systemImage: "nosign").tag(Optional(nil)) ForEach(tweakFolders, id:\.self) { folderName in Text(folderName).tag(Optional(folderName)) } } } label: { HStack { - Text("Tweak Folder") + Text("lc.appSettings.tweakFolder".loc) .foregroundColor(.primary) Spacer() Text(model.uiTweakFolder == nil ? "None" : model.uiTweakFolder!) @@ -153,103 +153,103 @@ struct LCAppSettingsView : View{ } else { HStack { - Text("Data Folder") + Text("lc.appSettings.dataFolder".loc) .foregroundColor(.primary) Spacer() - Text(model.uiDataFolder == nil ? "Data folder not created yet" : model.uiDataFolder!) + Text(model.uiDataFolder == nil ? "lc.appSettings.noDataFolder".loc : model.uiDataFolder!) .foregroundColor(.gray) .multilineTextAlignment(.trailing) } HStack { - Text("Tweak Folder") + Text("lc.appSettings.tweakFolder".loc) .foregroundColor(.primary) Spacer() - Text(model.uiTweakFolder == nil ? "None" : model.uiTweakFolder!) + Text(model.uiTweakFolder == nil ? "lc.common.none".loc : model.uiTweakFolder!) .foregroundColor(.gray) .multilineTextAlignment(.trailing) } } if !model.uiIsShared { - Button("Convert to Shared App") { + Button("lc.appSettings.toSharedApp".loc) { Task { await moveToAppGroup()} } } else if LCUtils.multiLCStatus != 2 { - Button("Convert to Private App") { + Button("lc.appSettings.toPrivateApp".loc) { Task { await movePrivateDoc() } } } } header: { - Text("Data") + Text("lc.common.data".loc) } Section { Toggle(isOn: $model.uiIsJITNeeded) { - Text("Launch with JIT") + Text("lc.appSettings.launchWithJit".loc) } .onChange(of: model.uiIsJITNeeded, perform: { newValue in Task { await setJITNeeded(newValue) } }) } footer: { - Text("LiveContainer will try to acquire JIT permission before launching the app.") + Text("lc.appSettings.launchWithJitDesc".loc) } if sharedModel.isHiddenAppUnlocked { Section { Toggle(isOn: $model.uiIsHidden) { - Text("Hide App") + Text("lc.appSettings.hideApp".loc) } .onChange(of: model.uiIsHidden, perform: { newValue in Task { await toggleHidden() } }) } footer: { - Text("To completely hide apps, enable Strict Hiding mode in settings.") + Text("lc.appSettings.hideAppDesc".loc) } } Section { Toggle(isOn: $model.uiDoSymlinkInbox) { - Text("Fix File Picker") + Text("lc.appSettings.fixFilePicker".loc) } .onChange(of: model.uiDoSymlinkInbox, perform: { newValue in Task { await setSimlinkInbox(newValue) } }) } header: { - Text("Fixes") + Text("lc.appSettings.fixes".loc) } footer: { - Text("Fix file picker not responding when hitting 'open' by forcing this app to copy selected files to its inbox. You may view imported files in the 'Inbox' folder in app's data folder.") + Text("lc.appSettings.fixFilePickerDesc".loc) } Section { Toggle(isOn: $model.uiBypassAssertBarrierOnQueue) { - Text("Bypass AssertBarrierOnQueue") + Text("lc.appSettings.bypassAssert".loc) } .onChange(of: model.uiBypassAssertBarrierOnQueue, perform: { newValue in Task { await setBypassAssertBarrierOnQueue(newValue) } }) } footer: { - Text("Might prevent some games from crashing, but may cause them to be unstable.") + Text("lc.appSettings.bypassAssertDesc".loc) } Section { - Button("Force Sign") { + Button("lc.appSettings.forceSign".loc) { Task { await forceResign() } } .disabled(model.isAppRunning) } footer: { - Text("Try to sign again if this app failed to launch with error like 'Invalid Signature'. It this still don't work, renew JIT-Less certificate.") + Text("lc.appSettings.forceSignDesc".loc) } } .navigationTitle(appInfo.displayName()) - .alert("Error", isPresented: $errorShow) { - Button("OK", action: { + .alert("lc.common.error".loc, isPresented: $errorShow) { + Button("lc.common.ok".loc, action: { }) } message: { Text(errorInfo) @@ -257,7 +257,7 @@ struct LCAppSettingsView : View{ .textFieldAlert( isPresented: $renameFolderShow, - title: "Enter the name of new folder", + title: "lc.common.enterNewFolderName".loc, text: $renameFolderContent, placeholder: "", action: { newText in @@ -269,33 +269,33 @@ struct LCAppSettingsView : View{ renameFolerContinuation?.resume() } ) - .alert("Move to App Group", isPresented: $confirmMoveToAppGroupShow) { + .alert("lc.appSettings.toSharedApp".loc, isPresented: $confirmMoveToAppGroupShow) { Button { self.confirmMoveToAppGroup = true self.confirmMoveToAppGroupContinuation?.resume() } label: { - Text("Move") + Text("lc.common.move".loc) } - Button("Cancel", role: .cancel) { + Button("lc.common.cancel".loc, role: .cancel) { self.confirmMoveToAppGroup = false self.confirmMoveToAppGroupContinuation?.resume() } } message: { - Text("Moving this app to App Group allows other LiveContainers to run this app with all its data and tweak preserved. If you want to access its data and tweak again from the file app, move it back.") + Text("lc.appSettings.toSharedAppDesc".loc) } - .alert("Move to Private Document Folder", isPresented: $confirmMoveToPrivateDocShow) { + .alert("lc.appSettings.toPrivateApp".loc, isPresented: $confirmMoveToPrivateDocShow) { Button { self.confirmMoveToPrivateDoc = true self.confirmMoveToPrivateDocContinuation?.resume() } label: { - Text("Move") + Text("lc.common.move".loc) } - Button("Cancel", role: .cancel) { + Button("lc.common.cancel".loc, role: .cancel) { self.confirmMoveToPrivateDoc = false self.confirmMoveToPrivateDocContinuation?.resume() } } message: { - Text("Moving this app to Private Document Folder allows you to access its data and tweaks in the Files app, but it can not be run by other LiveContainers.") + Text("lc.appSettings.toPrivateAppDesc".loc) } } @@ -412,7 +412,7 @@ struct LCAppSettingsView : View{ func movePrivateDoc() async { let runningLC = LCUtils.getAppRunningLCScheme(bundleId: appInfo.relativeBundlePath!) if runningLC != nil { - errorInfo = "Data of this app is currently in \(runningLC!). Open \(runningLC!) and launch it to 'My Apps' screen and try again." + errorInfo = "lc.appSettings.appOpenInOtherLc %@ %@".localizeWithFormat(runningLC!, runningLC!) errorShow = true return } diff --git a/LiveContainerSwiftUI/LCSettingsView.swift b/LiveContainerSwiftUI/LCSettingsView.swift index 7eb6d85..94a8feb 100644 --- a/LiveContainerSwiftUI/LCSettingsView.swift +++ b/LiveContainerSwiftUI/LCSettingsView.swift @@ -75,15 +75,15 @@ struct LCSettingsView: View { setupJitLess() } label: { if isJitLessEnabled { - Text("Renew JIT-less certificate") + Text("lc.settings.renewJitLess".loc) } else { - Text("Setup JIT-less certificate") + Text("lc.settings.setupJitLess".loc) } } } header: { - Text("JIT-Less") + Text("lc.settings.jitLess".loc) } footer: { - Text("JIT-less allows you to use LiveContainer without having to enable JIT. Requires AltStore or SideStore.") + Text("lc.settings.jitLessDesc".loc) } } @@ -92,48 +92,39 @@ struct LCSettingsView: View { installAnotherLC() } label: { if LCUtils.multiLCStatus == 0 { - Text("Install another LiveContainer") + Text("lc.settings.multiLCInstall".loc) } else if LCUtils.multiLCStatus == 1 { - Text("Reinstall another LiveContainer") + Text("lc.settings.multiLCReinstall".loc) } else if LCUtils.multiLCStatus == 2 { - Text("This is the second LiveContainer") + Text("lc.settings.multiLCIsSecond".loc) } } .disabled(LCUtils.multiLCStatus == 2) } header: { - Text("Multiple LiveContainers") + Text("lc.settings.multiLC".loc) } footer: { - Text("By installing multiple LiveContainers, and converting apps to Shared Apps, you can open one app between all LiveContainers with most of its data and settings.") + Text("lc.settings.multiLCDesc".loc) } Section { Toggle(isOn: $isAltCertIgnored) { - Text("Ignore ALTCertificate.p12") + Text("lc.settings.ignoreAltCert".loc) } } footer: { - Text("If you see frequent re-sign, enable this option.") + Text("lc.settings.ignoreAltCertDesc".loc) } - Section{ - Toggle(isOn: $frameShortIcon) { - Text("Frame Short Icon") - } - } header: { - Text("Miscellaneous") - } footer: { - Text("Frame shortcut icons with LiveContainer icon.") - } Section { HStack { - Text("Address") + Text("lc.settings.JitAddress".loc) Spacer() TextField("http://x.x.x.x:8080", text: $sideJITServerAddress) .multilineTextAlignment(.trailing) } HStack { - Text("UDID") + Text("lc.settings.JitUDID".loc) Spacer() TextField("", text: $deviceUDID) .multilineTextAlignment(.trailing) @@ -141,32 +132,42 @@ struct LCSettingsView: View { } header: { Text("JIT") } footer: { - Text("Set up your SideJITServer/JITStreamer server. Local Network permission is required.") + Text("lc.settings.JitDesc".loc) + } + + Section{ + Toggle(isOn: $frameShortIcon) { + Text("lc.settings.FrameIcon".loc) + } + } header: { + Text("lc.common.miscellaneous".loc) + } footer: { + Text("lc.settings.FrameIconDesc".loc) } Section { Toggle(isOn: $silentSwitchApp) { - Text("Switch App Without Asking") + Text("lc.settings.silentSwitchApp".loc) } } footer: { - Text("By default, LiveContainer asks you before switching app. Enable this to switch app immediately. Any unsaved data will be lost.") + Text("lc.settings.silentSwitchAppDesc".loc) } Section { Toggle(isOn: $injectToLCItelf) { - Text("Load Tweaks to LiveContainer Itself") + Text("lc.settings.injectLCItself".loc) } } footer: { - Text("Place your tweaks into the global “Tweaks” folder and LiveContainer will pick them up.") + Text("lc.settings.injectLCItselfDesc".loc) } if sharedModel.isHiddenAppUnlocked { Section { Toggle(isOn: $strictHiding) { - Text("Strict Hiding Mode") + Text("lc.settings.strictHiding".loc) } } footer: { - Text("Enabling this mode will only allow hidden apps to be launched by triple clicking the installed app counter.") + Text("lc.settings.strictHidingDesc".loc) } } @@ -175,31 +176,50 @@ struct LCSettingsView: View { Button { moveAppGroupFolderFromPrivateToAppGroup() } label: { - Text("Move Private App Group to Shared Documents Folder") + Text("lc.settings.appGroupPrivateToShare".loc) } Button { moveAppGroupFolderFromAppGroupToPrivate() } label: { - Text("Move Shared App Group Files to Private Documents Folder") + Text("lc.settings.appGroupShareToPrivate".loc) } Button { Task { await moveDanglingFolders() } } label: { - Text("Move Dangling Folders Out of App Group") + Text("lc.settings.moveDanglingFolderOut".loc) } Button(role:.destructive) { Task { await cleanUpUnusedFolders() } } label: { - Text("Clean Unused Data Folders") + Text("lc.settings.cleanDataFolder".loc) } } Button(role:.destructive) { Task { await removeKeyChain() } } label: { - Text("Clean Up Keychain") + Text("lc.settings.cleanKeychain".loc) + } + } + + Section { + HStack { + Image("GitHub") + Button("khanhduytran0/LiveContainer") { + openGitHub() + } + } + HStack { + Image("Twitter") + Button("@TranKha50277352") { + openTwitter() + } } + } header: { + Text("lc.settings.about".loc) + } footer: { + Text("lc.settings.warning".loc) } VStack{ @@ -210,51 +230,51 @@ struct LCSettingsView: View { .background(Color(UIColor.systemGroupedBackground)) .listRowInsets(EdgeInsets()) } - .navigationBarTitle("Settings") - .alert("Error", isPresented: $errorShow){ + .navigationBarTitle("lc.tabView.settings".loc) + .alert("lc.common.error".loc, isPresented: $errorShow){ } message: { Text(errorInfo) } - .alert("Success", isPresented: $successShow){ + .alert("lc.common.success".loc, isPresented: $successShow){ } message: { Text(successInfo) } - .alert("Data Folder Clean Up", isPresented: $confirmAppFolderRemovalShow) { + .alert("lc.settings.cleanDataFolder".loc, isPresented: $confirmAppFolderRemovalShow) { if folderRemoveCount > 0 { Button(role: .destructive) { self.confirmAppFolderRemoval = true self.appFolderRemovalContinuation?.resume() } label: { - Text("Delete") + Text("lc.common.delete".loc) } } - Button("Cancel", role: .cancel) { + Button("lc.common.cancel".loc, role: .cancel) { self.confirmAppFolderRemoval = false self.appFolderRemovalContinuation?.resume() } } message: { if folderRemoveCount > 0 { - Text("Do you want to delete \(folderRemoveCount) unused data folder(s)?") + Text("lc.settings.cleanDataFolderConfirm".localizeWithFormat(folderRemoveCount)) } else { - Text("No data folder to remove. All data folders are in use.") + Text("lc.settings.noDataFolderToClean".loc) } } - .alert("Keychain Clean Up", isPresented: $confirmKeyChainRemovalShow) { + .alert("lc.settings.cleanKeychain".loc, isPresented: $confirmKeyChainRemovalShow) { Button(role: .destructive) { self.confirmKeyChainRemoval = true self.confirmKeyChainContinuation?.resume() } label: { - Text("Delete") + Text("lc.common.delete".loc) } - Button("Cancel", role: .cancel) { + Button("lc.common.cancel".loc, role: .cancel) { self.confirmKeyChainRemoval = false self.confirmKeyChainContinuation?.resume() } } message: { - Text("If some app's account can not be synced between LiveContainers, it's may because it is still stored in current LiveContainer's private keychain. Cleaning up keychain may solve this issue, but it may sign you out of some of your accounts. Continue?") + Text("lc.settings.cleanKeychainDesc".loc) } .onChange(of: isAltCertIgnored) { newValue in saveItem(key: "LCIgnoreALTCertificate", val: newValue) @@ -292,7 +312,7 @@ struct LCSettingsView: View { func setupJitLess() { if !LCUtils.isAppGroupAltStoreLike() { - errorInfo = "Unsupported installation method. Please use AltStore or SideStore to setup this feature." + errorInfo = "lc.settings.unsupportedInstallMethod".loc errorShow = true return; } @@ -309,7 +329,7 @@ struct LCSettingsView: View { func installAnotherLC() { if !LCUtils.isAppGroupAltStoreLike() { - errorInfo = "Unsupported installation method. Please use AltStore or SideStore to setup this feature." + errorInfo = "lc.settings.unsupportedInstallMethod".loc errorShow = true return; } @@ -449,7 +469,7 @@ struct LCSettingsView: View { try fm.moveItem(at: LCPath.lcGroupTweakPath.appendingPathComponent(tweakFolderInUse), to: LCPath.tweakPath.appendingPathComponent(tweakFolderInUse)) movedTweakFolderCount += 1 } - successInfo = "Moved \(movedDataFolderCount) data folder(s) and \(movedTweakFolderCount) tweak folders." + successInfo = "lc.settings.moveDanglingFolderComplete %lld %lld".localizeWithFormat(movedDataFolderCount,movedTweakFolderCount) successShow = true } catch { @@ -471,14 +491,14 @@ struct LCSettingsView: View { let privateFolderContents = try fm.contentsOfDirectory(at: LCPath.appGroupPath, includingPropertiesForKeys: nil) let sharedFolderContents = try fm.contentsOfDirectory(at: LCPath.lcGroupAppGroupPath, includingPropertiesForKeys: nil) if privateFolderContents.count > 0 { - errorInfo = "There are files in the private app group folder. Clean it up and try again." + errorInfo = "lc.settings.appGroupExistPrivate".loc errorShow = true return } for file in sharedFolderContents { try fm.moveItem(at: file, to: LCPath.appGroupPath.appendingPathComponent(file.lastPathComponent)) } - successInfo = "Move success." + successInfo = "lc.settings.appGroup.moveSuccess".loc successShow = true } catch { @@ -500,14 +520,14 @@ struct LCSettingsView: View { let privateFolderContents = try fm.contentsOfDirectory(at: LCPath.appGroupPath, includingPropertiesForKeys: nil) let sharedFolderContents = try fm.contentsOfDirectory(at: LCPath.lcGroupAppGroupPath, includingPropertiesForKeys: nil) if sharedFolderContents.count > 0 { - errorInfo = "There are files in the shared app group folder. Move it out first and try again." + errorInfo = "lc.settings.appGroupExist Shared".loc errorShow = true return } for file in privateFolderContents { try fm.moveItem(at: file, to: LCPath.lcGroupAppGroupPath.appendingPathComponent(file.lastPathComponent)) } - successInfo = "Move success." + successInfo = "lc.settings.appGroup.moveSuccess".loc successShow = true } catch { @@ -515,4 +535,12 @@ struct LCSettingsView: View { errorShow = true } } + + func openGitHub() { + UIApplication.shared.open(URL(string: "https://github.com/khanhduytran0/LiveContainer")!) + } + + func openTwitter() { + UIApplication.shared.open(URL(string: "https://twitter.com/TranKha50277352")!) + } } diff --git a/LiveContainerSwiftUI/LCTabView.swift b/LiveContainerSwiftUI/LCTabView.swift index b2e2f81..274f578 100644 --- a/LiveContainerSwiftUI/LCTabView.swift +++ b/LiveContainerSwiftUI/LCTabView.swift @@ -92,24 +92,24 @@ struct LCTabView: View { TabView { LCAppListView(apps: $apps, hiddenApps: $hiddenApps, appDataFolderNames: $appDataFolderNames, tweakFolderNames: $tweakFolderNames) .tabItem { - Label("Apps", systemImage: "square.stack.3d.up.fill") + Label("lc.tabView.apps".loc, systemImage: "square.stack.3d.up.fill") } if LCUtils.multiLCStatus != 2 { LCTweaksView(tweakFolders: $tweakFolderNames) .tabItem{ - Label("Tweaks", systemImage: "wrench.and.screwdriver") + Label("lc.tabView.tweaks".loc, systemImage: "wrench.and.screwdriver") } } LCSettingsView(apps: $apps, hiddenApps: $hiddenApps, appDataFolderNames: $appDataFolderNames) .tabItem { - Label("Settings", systemImage: "gearshape.fill") + Label("lc.tabView.settings".loc, systemImage: "gearshape.fill") } } - .alert("Error", isPresented: $errorShow){ - Button("OK", action: { + .alert("lc.common.error".loc, isPresented: $errorShow){ + Button("lc.common.ok".loc, action: { }) - Button("Copy", action: { + Button("lc.common.copy".loc, action: { copyError() }) } message: { diff --git a/LiveContainerSwiftUI/LCTweaksView.swift b/LiveContainerSwiftUI/LCTweaksView.swift index f6ab917..8f16af6 100644 --- a/LiveContainerSwiftUI/LCTweaksView.swift +++ b/LiveContainerSwiftUI/LCTweaksView.swift @@ -87,13 +87,13 @@ struct LCTweakFolderView : View { Button { Task { await renameTweakItem(tweakItem: tweakItem)} } label: { - Label("Rename", systemImage: "pencil") + Label("lc.common.rename".loc, systemImage: "pencil") } Button(role: .destructive) { deleteTweakItem(tweakItem: tweakItem) } label: { - Label("Delete", systemImage: "trash") + Label("lc.common.delete".loc, systemImage: "trash") } } @@ -104,11 +104,11 @@ struct LCTweakFolderView : View { Section { VStack{ if isRoot { - Text("This is the global folder. All tweaks put here will be injected to all guest apps. Create a new folder if you use app-specific tweaks.") + Text("lc.tweakView.globalFolderDesc".loc) .foregroundStyle(.gray) .font(.system(size: 12)) } else { - Text("This is the app-specific folder. Set the tweak folder and the guest app will pick them up recursively.") + Text("lc.tweakView.appFolderDesc".loc) .foregroundStyle(.gray) .font(.system(size: 12)) } @@ -120,14 +120,14 @@ struct LCTweakFolderView : View { } } - .navigationTitle(baseUrl.lastPathComponent) + .navigationTitle(isRoot ? "lc.tabView.tweaks".loc : baseUrl.lastPathComponent) .toolbar { ToolbarItem(placement: .topBarTrailing) { if !isTweakSigning && LCUtils.certificatePassword() != nil { Button { Task { await signAllTweaks() } } label: { - Label("sign", systemImage: "signature") + Label("sign".loc, systemImage: "signature") } } @@ -145,13 +145,13 @@ struct LCTweakFolderView : View { choosingTweak = true } } label: { - Label("Import Tweak", systemImage: "square.and.arrow.down") + Label("lc.tweakView.importTweak".loc, systemImage: "square.and.arrow.down") } Button { Task { await createNewFolder() } } label: { - Label("New folder", systemImage: "folder.badge.plus") + Label("lc.tweakView.newFolder".loc, systemImage: "folder.badge.plus") } } label: { Label("add", systemImage: "plus") @@ -162,15 +162,15 @@ struct LCTweakFolderView : View { } } - .alert("Error", isPresented: $errorShow) { - Button("OK", action: { + .alert("lc.common.error".loc, isPresented: $errorShow) { + Button("lc.common.ok".loc, action: { }) } message: { Text(errorInfo) } .textFieldAlert( isPresented: $newFolderShow, - title: "Enter the name of new folder", + title: "lc.common.enterNewFolderName".loc, text: $newFolderContent, placeholder: "", action: { newText in @@ -184,7 +184,7 @@ struct LCTweakFolderView : View { ) .textFieldAlert( isPresented: $renameFileShow, - title: "Enter New Name", + title: "lc.common.enterNewName".loc, text: $renameFileContent, placeholder: "", action: { newText in @@ -199,12 +199,6 @@ struct LCTweakFolderView : View { .fileImporter(isPresented: $choosingTweak, allowedContentTypes: [.dylib, .lcFramework, .deb], allowsMultipleSelection: true) { result in Task { await startInstallTweak(result) } } - .alert("Error", isPresented: $errorShow) { - Button("OK", action: { - }) - } message: { - Text(errorInfo) - } } func deleteTweakItem(indexSet: IndexSet) { @@ -387,10 +381,10 @@ struct LCTweakFolderView : View { for fileUrl in urls { // handle deb file if(!fileUrl.startAccessingSecurityScopedResource()) { - throw "Cannot open \(fileUrl.lastPathComponent), permission denied." + throw "lc.tweakView.permissionDenied %@".localizeWithFormat(fileUrl.lastPathComponent) } if(!fileUrl.isFileURL) { - throw "\(fileUrl.absoluteString), is not a file." + throw "lc.tweakView.notFileError %@".localizeWithFormat(fileUrl.lastPathComponent) } let toPath = tmpDir.appendingPathComponent(fileUrl.lastPathComponent) try fm.copyItem(at: fileUrl, to: toPath) diff --git a/LiveContainerSwiftUI/LCWebView.swift b/LiveContainerSwiftUI/LCWebView.swift index 41f2640..ae89465 100644 --- a/LiveContainerSwiftUI/LCWebView.swift +++ b/LiveContainerSwiftUI/LCWebView.swift @@ -69,7 +69,7 @@ struct LCWebView: View { Button(action: { isPresent = false }, label: { - Text("Done") + Text("lc.common.done".loc) }) } @@ -101,20 +101,20 @@ struct LCWebView: View { } } - .alert("Run App", isPresented: $runAppAlertShow) { - Button("Run", action: { + .alert("lc.webView.runApp".loc, isPresented: $runAppAlertShow) { + Button("lc.appBanner.run".loc, action: { self.doRunApp = true self.doRunAppContinuation?.resume() }) - Button("Cancel", role: .cancel, action: { + Button("lc.common.cancel".loc, role: .cancel, action: { self.doRunApp = false self.doRunAppContinuation?.resume() }) } message: { Text(runAppAlertMsg) } - .alert("Error", isPresented: $errorShow) { - Button("OK", action: { + .alert("lc.common.error".loc, isPresented: $errorShow) { + Button("lc.common.ok".loc, action: { }) } message: { Text(errorInfo) @@ -169,7 +169,7 @@ struct LCWebView: View { guard let appToLaunch = appToLaunch else { - errorInfo = "Scheme \"\(url.scheme!)\" cannot be opened by any app installed in LiveContainer." + errorInfo = "lc.appList.schemeCannotOpenError %@".localizeWithFormat(url.scheme!) errorShow = true return } @@ -187,7 +187,7 @@ struct LCWebView: View { } } - runAppAlertMsg = "This web page is trying to launch \"\(appToLaunch.displayName()!)\", continue?" + runAppAlertMsg = "lc.webView.pageLaunch %@".localizeWithFormat(appToLaunch.displayName()!) await withCheckedContinuation { c in self.doRunAppContinuation = c @@ -236,7 +236,7 @@ struct LCWebView: View { } } - runAppAlertMsg = "This web page can be opened in \"\(appToLaunch.displayName()!)\" according to its Associated Domains, continue?" + runAppAlertMsg = "lc.webView.pageCanBeOpenIn %@".localizeWithFormat(appToLaunch.displayName()!) runAppAlertShow = true await withCheckedContinuation { c in self.doRunAppContinuation = c diff --git a/LiveContainerSwiftUI/LiveContainerSwiftUI.xcodeproj/project.pbxproj b/LiveContainerSwiftUI/LiveContainerSwiftUI.xcodeproj/project.pbxproj index 2dbc0fc..c05bbad 100644 --- a/LiveContainerSwiftUI/LiveContainerSwiftUI.xcodeproj/project.pbxproj +++ b/LiveContainerSwiftUI/LiveContainerSwiftUI.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 170C3DF92C99A489007F86FB /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 170C3DF82C99A489007F86FB /* Localizable.xcstrings */; }; 173564C92C76FE3500C6C918 /* LCAppListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 173564BC2C76FE3500C6C918 /* LCAppListView.swift */; }; 173564CA2C76FE3500C6C918 /* LCTabView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 173564BD2C76FE3500C6C918 /* LCTabView.swift */; }; 173564CC2C76FE3500C6C918 /* LCTweaksView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 173564C02C76FE3500C6C918 /* LCTweaksView.swift */; }; @@ -22,6 +23,7 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 170C3DF82C99A489007F86FB /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Localizable.xcstrings; sourceTree = ""; }; 173564BC2C76FE3500C6C918 /* LCAppListView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LCAppListView.swift; sourceTree = ""; }; 173564BD2C76FE3500C6C918 /* LCTabView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LCTabView.swift; sourceTree = ""; }; 173564C02C76FE3500C6C918 /* LCTweaksView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LCTweaksView.swift; sourceTree = ""; }; @@ -67,6 +69,7 @@ 178B4C3D2C77654400DD1F74 /* Shared.swift */, 173564C22C76FE3500C6C918 /* LCSwiftBridge.h */, 173564C42C76FE3500C6C918 /* LCSwiftBridge.m */, + 170C3DF82C99A489007F86FB /* Localizable.xcstrings */, ); name = LiveContainerSwiftUI; sourceTree = ""; @@ -129,44 +132,8 @@ knownRegions = ( en, Base, - de, - he, - en_AU, - ar, - el, - ja, - uk, - es_419, zh_CN, - es, - pt_BR, - da, - it, - sk, - pt_PT, - ms, - sv, - cs, - ko, no, - hu, - zh_HK, - tr, - pl, - zh_TW, - en_GB, - vi, - ru, - fr_CA, - fr, - fi, - id, - nl, - th, - ro, - hr, - hi, - ca, ); mainGroup = 17B9B8842C760678009D079E; productRefGroup = 17B9B88E2C760678009D079E /* Products */; @@ -183,6 +150,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 170C3DF92C99A489007F86FB /* Localizable.xcstrings in Resources */, 173564D32C76FE3500C6C918 /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -263,7 +231,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 17.5; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LOCALIZATION_PREFERS_STRING_CATALOGS = YES; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; @@ -320,7 +288,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 17.5; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LOCALIZATION_PREFERS_STRING_CATALOGS = YES; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; @@ -337,7 +305,6 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_ASSET_PATHS = "\"LiveContainerSwiftUI/Preview Content\""; DEVELOPMENT_TEAM = ""; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; @@ -371,7 +338,6 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_ASSET_PATHS = "\"LiveContainerSwiftUI/Preview Content\""; DEVELOPMENT_TEAM = ""; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; diff --git a/LiveContainerSwiftUI/Localizable.xcstrings b/LiveContainerSwiftUI/Localizable.xcstrings new file mode 100644 index 0000000..4a8a083 --- /dev/null +++ b/LiveContainerSwiftUI/Localizable.xcstrings @@ -0,0 +1,2212 @@ +{ + "sourceLanguage" : "en", + "strings" : { + "lc.appBanner.addToHomeScreen" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Add to Home Screen" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "添加到主屏幕" + } + } + } + }, + "lc.appBanner.confirmUninstallMsg %@" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Are you sure you want to uninstall %@?" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "你确定要卸载%@吗?" + } + } + } + }, + "lc.appBanner.confirmUninstallTitle" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Confirm Uninstallation" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "确认卸载" + } + } + } + }, + "lc.appBanner.copyLaunchUrl" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Copy Launch Url" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "复制启动链接" + } + } + } + }, + "lc.appBanner.createAppClip" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Create App Clip" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "创建AppClip" + } + } + } + }, + "lc.appBanner.deleteDataMsg %@" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Do you also want to delete data folder of %@? You can keep it for future use." + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "你希望删除%@的数据吗?你可以保留以便以后使用" + } + } + } + }, + "lc.appBanner.deleteDataTitle" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Delete Data Folder" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "删除数据" + } + } + } + }, + "lc.appBanner.jitLaunchNow" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Launch Now" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "立即启动" + } + } + } + }, + "lc.appBanner.noDataFolder" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Data folder not created yet" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "数据文件夹未创建" + } + } + } + }, + "lc.appBanner.openDataFolder" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Open Data Folder" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "打开数据文件夹" + } + } + } + }, + "lc.appBanner.run" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Run" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "启动" + } + } + } + }, + "lc.appBanner.saveAppIcon" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Save App Icon" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "保存App图标" + } + } + } + }, + "lc.appBanner.shared" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "SHARED" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "共享" + } + } + } + }, + "lc.appBanner.uninstall" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Uninstall" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "卸载" + } + } + } + }, + "lc.appBanner.waitForJitMsg" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Please use your favourite way to enable jit for current LiveContainer." + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "请为LiveContainer启用JIT。" + } + } + } + }, + "lc.appBanner.waitForJitTitle" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Waiting for JIT" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "等待JIT" + } + } + } + }, + "lc.appList.abortInstallation" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Abort Installation" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "终止安装" + } + } + } + }, + "lc.appList.appCounter %lld" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld App in total" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld Apps in total" + } + } + } + } + }, + "zh_CN" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "共%lld个App" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "共%lld个App" + } + } + } + } + } + } + }, + "lc.appList.appInfoInitError" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Failed to Initialize AppInfo!" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "初始化AppInfo失败!" + } + } + } + }, + "lc.appList.appNotFoundError" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "App not Found." + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "未找到App!" + } + } + } + }, + "lc.appList.bundleNotFondError" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "App bundle not found." + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "未找到App包。" + } + } + } + }, + "lc.appList.enterUrlTip" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Enter Url or Url Scheme" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "请输入链接" + } + } + } + }, + "lc.appList.hiddenApps" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Hidden Apps" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "隐藏App" + } + } + } + }, + "lc.appList.hideAppTip" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Hide app in app settings." + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "在App设置中可隐藏App" + } + } + } + }, + "lc.appList.infoPlistCannotReadError" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Failed to read app's Info.plist." + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "读取Info.plist失败。" + } + } + } + }, + "lc.appList.installAsNew" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Install as new" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "安装为新App" + } + } + } + }, + "lc.appList.installation" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Installation" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "安装" + } + } + } + }, + "lc.appList.installReplaceTip" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "There is an existing application with the same bundle identifier. Replace one or install as new." + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "已有相同包名的App存在。请从下列App中选择一个替换或安装为新App。" + } + } + } + }, + "lc.appList.installTip" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Press the Plus Button to Install Apps." + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "点击加号按钮安装App" + } + } + } + }, + "lc.appList.ipaAccessError" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Failed to access IPA" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "无法读取IPA。" + } + } + } + }, + "lc.appList.manageInPrimaryTip" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Manage apps in the primary LiveContainer" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "请在主LiveContainer中管理App" + } + } + } + }, + "lc.appList.myApps" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "My Apps" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "App" + } + } + } + }, + "lc.appList.openLink" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Open Link" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "打开链接" + } + } + } + }, + "lc.appList.schemeCannotOpenError %@" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Scheme \"%@\" cannot be opened by any app installed in LiveContainer." + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "协议“%@”无法被LiveContainer中安装的任何App打开。" + } + } + } + }, + "lc.appList.urlInvalidError" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "The input url is invalid. Please check and try again" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "输入的链接无效,请检查后重试。" + } + } + } + }, + "lc.appSettings.appOpenInOtherLc %@ %@" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Data of this app is currently in %@. Open %@ and launch it to 'My Apps' screen and try again." + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "此App的数据当前在%@中。打开%@至App界面活后再试。" + } + } + } + }, + "lc.appSettings.bundleId" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bundle Identifier" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "包名" + } + } + } + }, + "lc.appSettings.bypassAssert" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bypass AssertBarrierOnQueue" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "绕过AssertBarrierOnQueue" + } + } + } + }, + "lc.appSettings.bypassAssertDesc" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Might prevent some games from crashing, but may cause them to be unstable." + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "可能解决一些游戏崩溃的问题,但可能使得游戏变得不稳定。" + } + } + } + }, + "lc.appSettings.dataFolder" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Data Folder" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "数据文件夹" + } + } + } + }, + "lc.appSettings.fixes" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fixes" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "修复" + } + } + } + }, + "lc.appSettings.fixFilePicker" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fix File Picker" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "修复文件导入" + } + } + } + }, + "lc.appSettings.fixFilePickerDesc" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fix file picker not responding when hitting 'open' by forcing this app to copy selected files to its inbox. You may view imported files in the 'Inbox' folder in app's data folder." + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "若导入文件时点击“打开”没有反应,可启用本选项。启用后所有导入的文件会被复制到App数据文件夹的Inbox目录下。" + } + } + } + }, + "lc.appSettings.forceSign" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Force Sign" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "强制重新签名" + } + } + } + }, + "lc.appSettings.forceSignDesc" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Try to sign again if this app failed to launch with error like 'Invalid Signature'. If this still don't work, renew JIT-Less certificate." + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "如果App启动时的报错包含“Invalid Signature”,则可以尝试强制重新签名。如果仍然报错,则可能需要刷新免JIT证书。" + } + } + } + }, + "lc.appSettings.hideApp" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Hide App" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "隐藏App" + } + } + } + }, + "lc.appSettings.hideAppDesc" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "To completely hide apps, enable Strict Hiding mode in settings." + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "要完全隐藏App,请在设置中启用严格隐藏模式。" + } + } + } + }, + "lc.appSettings.launchWithJit" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Launch with JIT" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "带JIT启动" + } + } + } + }, + "lc.appSettings.launchWithJitDesc" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "LiveContainer will try to acquire JIT permission before launching the app." + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "在启动App前LiveContainer会尝试获取JIT权限。" + } + } + } + }, + "lc.appSettings.newDataFolder" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "New data folder" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "创建新的数据文件夹" + } + } + } + }, + "lc.appSettings.noDataFolder" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Not Created Yet" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "未创建" + } + } + } + }, + "lc.appSettings.renameDataFolder" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Rename data folder" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "重命名数据文件夹" + } + } + } + }, + "lc.appSettings.toPrivateApp" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Convert to Private App" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "转换为私有App" + } + } + } + }, + "lc.appSettings.toPrivateAppDesc" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Moving this app to Private Document Folder allows you to access its data and tweaks in the Files app, but it can not be run by other LiveContainers." + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "将App此转换为私有App允许您在文件App中访问其数据和模块,但它不能由其他LiveContainers运行。" + } + } + } + }, + "lc.appSettings.toSharedApp" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Convert to Shared App" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "转换为共享App" + } + } + } + }, + "lc.appSettings.toSharedAppDesc" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Moving this app to App Group allows other LiveContainers to run this app with all its data and tweak preserved. If you want to access its data and tweak again from the file app, move it back." + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "将此App移动到AppGroup以允许其他LiveContainers运行此App,并保留其所有数据和模块。如果你想访问它的数据和模块,请将其转换为私有App。" + } + } + } + }, + "lc.appSettings.tweakFolder" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tweak Folder" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "模块文件夹" + } + } + } + }, + "lc.common.cancel" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cancel" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "取消" + } + } + } + }, + "lc.common.copy" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Copy" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "复制" + } + } + } + }, + "lc.common.data" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Data" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "数据" + } + } + } + }, + "lc.common.delete" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Delete" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "删除" + } + } + } + }, + "lc.common.done" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Done" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "完成" + } + } + } + }, + "lc.common.enterNewFolderName" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Enter the name of new folder" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "输入新文件夹的名称" + } + } + } + }, + "lc.common.enterNewName" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Enter New Name" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "输入新名称" + } + } + } + }, + "lc.common.error" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Error" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "错误" + } + } + } + }, + "lc.common.miscellaneous" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Miscellaneous" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "杂项" + } + } + } + }, + "lc.common.move" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Move" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "移动" + } + } + } + }, + "lc.common.none" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "None" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "无" + } + } + } + }, + "lc.common.ok" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "OK" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "好" + } + } + } + }, + "lc.common.rename" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Rename" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "重命名" + } + } + } + }, + "lc.common.success" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Success" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "成功" + } + } + } + }, + "lc.settings.about" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "About Me" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "关于" + } + } + } + }, + "lc.settings.appGroup.moveSuccess" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Move success." + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "移动完成。" + } + } + } + }, + "lc.settings.appGroupExist Shared" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "There are files in the shared app group folder. Move it out first and try again." + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "共享的AppGroup文件夹中不为空。将其中文件移动出来后再试。" + } + } + } + }, + "lc.settings.appGroupExistPrivate" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "There are files in the private app group folder. Move it out first and try again." + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "私有的AppGroup文件夹中不为空。将其中文件移动出来后再试。" + } + } + } + }, + "lc.settings.appGroupPrivateToShare" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Move Private App Group to Shared Documents Folder" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "移动私有AppGroup文件到共享文件夹" + } + } + } + }, + "lc.settings.appGroupShareToPrivate" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Move Shared App Group Files to Private Documents Folder" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "移动共享AppGroup文件到私有文件夹" + } + } + } + }, + "lc.settings.cleanDataFolder" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Clean Unused Data Folders" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "清理未使用的数据文件夹" + } + } + } + }, + "lc.settings.cleanDataFolderConfirm %lld" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "Do you want to delete %lld unused data folder?" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "Do you want to delete %lld unused data folders?" + } + } + } + } + }, + "zh_CN" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "你确定要删除%lld个未使用的文件夹吗?" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "你确定要删除%lld个未使用的文件夹吗?" + } + } + } + } + } + } + }, + "lc.settings.cleanKeychain" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Clean Up Keychain" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "清理Keychain" + } + } + } + }, + "lc.settings.cleanKeychainDesc" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "If some app's account can not be synced between LiveContainers, it's may because it is still stored in current LiveContainer's private keychain. Cleaning up keychain may solve this issue, but it may sign you out of some of your accounts. Continue?" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "某些App的账户不能在LiveContainer间同步的原因可能是其Keychain还存储在本地。清理Keychain可能能解决此问题,但可能会导致你登出某些账户。要继续吗?" + } + } + } + }, + "lc.settings.FrameIcon" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Frame Short Icon" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "在App图标外加边框" + } + } + } + }, + "lc.settings.FrameIconDesc" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Frame shortcut icons with LiveContainer icon." + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "在App图标外加LiveContainer图标边框。" + } + } + } + }, + "lc.settings.ignoreAltCert" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ignore ALTCertificate.p12" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "忽略ALTCertificate.p12" + } + } + } + }, + "lc.settings.ignoreAltCertDesc" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "If you see frequent re-sign, enable this option." + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "如果App重新签名过于频繁,可尝试启用此项。" + } + } + } + }, + "lc.settings.injectLCItself" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Load Tweaks to LiveContainer Itself" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "向LiveContainer加载模块" + } + } + } + }, + "lc.settings.injectLCItselfDesc" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Place your tweaks into the global “Tweaks” folder and LiveContainer will pick them up." + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "启用后,LiveContainer自身会加载全局模块文件夹中的模块。" + } + } + } + }, + "lc.settings.JitAddress" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Address" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "地址" + } + } + } + }, + "lc.settings.JitDesc" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Set up your SideJITServer/JITStreamer server. Local Network permission is required." + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "配置SideJITServer/JITStreamer。需要本地网络权限。" + } + } + } + }, + "lc.settings.jitLess" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "JIT-Less" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "免JIT模式" + } + } + } + }, + "lc.settings.jitLessDesc" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "JIT-less allows you to use LiveContainer without having to enable JIT. Requires AltStore or SideStore." + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "配置免JIT模式后,LiveContainer无需JIT即可使用。需要SideStore或AltStore。" + } + } + } + }, + "lc.settings.JitUDID" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "UDID" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "UDID" + } + } + } + }, + "lc.settings.moveDanglingFolderComplete %lld %lld" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Moved %#@arg1@ and %#@arg2@." + }, + "substitutions" : { + "arg1" : { + "argNum" : 1, + "formatSpecifier" : "lld", + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "%arg data folder" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "%arg data folders" + } + } + } + } + }, + "arg2" : { + "argNum" : 2, + "formatSpecifier" : "lld", + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "%arg tweak folder" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "%arg tweak folders" + } + } + } + } + } + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "移动了 %#@arg1@和 %#@arg2@。" + }, + "substitutions" : { + "arg1" : { + "argNum" : 1, + "formatSpecifier" : "lld", + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "%arg个数据文件夹" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "%arg个数据文件夹" + } + } + } + } + }, + "arg2" : { + "argNum" : 2, + "formatSpecifier" : "lld", + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "%arg个模块文件夹" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "%arg个模块文件夹" + } + } + } + } + } + } + } + } + }, + "lc.settings.moveDanglingFolderOut" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Move Dangling Folders Out of App Group" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "将未使用的文件夹移出AppGroup" + } + } + } + }, + "lc.settings.multiLC" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Multiple LiveContainers" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "多LiveContainer" + } + } + } + }, + "lc.settings.multiLCDesc" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "By installing multiple LiveContainers, and converting apps to Shared Apps, you can open one app between all LiveContainers with most of its data and settings." + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "通过安装多个LiveContainer,并将App变为共享App,你可以在这些LiveContainer间共享安装的App及其数据,并同时运行多个App。" + } + } + } + }, + "lc.settings.multiLCInstall" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Install another LiveContainer" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "安装第二个LiveContainer" + } + } + } + }, + "lc.settings.multiLCIsSecond" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "This is the second LiveContainer" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "这是第二个LiveContainer" + } + } + } + }, + "lc.settings.multiLCReinstall" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Reinstall another LiveContainer" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "重新安装第二个LiveContainer" + } + } + } + }, + "lc.settings.noDataFolderToClean" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "No data folder to remove. All data folders are in use." + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "未删除任何数据文件夹,所有文件夹都已被使用。" + } + } + } + }, + "lc.settings.renewJitLess" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Renew JIT-less certificate" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "刷新免JIT模式证书" + } + } + } + }, + "lc.settings.setupJitLess" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Setup JIT-less certificate" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "设置免JIT模式证书" + } + } + } + }, + "lc.settings.silentSwitchApp" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Switch App Without Asking" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "静默切换App" + } + } + } + }, + "lc.settings.silentSwitchAppDesc" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "By default, LiveContainer asks you before switching app. Enable this to switch app immediately. Any unsaved data will be lost." + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "LiveContainer在切换App时默认会向你确认。启用此选项来静默切换,所有未保存的数将会丢失。" + } + } + } + }, + "lc.settings.strictHiding" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Strict Hiding Mode" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "严格隐藏模式" + } + } + } + }, + "lc.settings.strictHidingDesc" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Enabling this mode will only allow hidden apps to be launched by triple clicking the installed app counter." + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "启用后,将只能从App选择界面启动App。" + } + } + } + }, + "lc.settings.unsupportedInstallMethod" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Unsupported installation method. Please use AltStore or SideStore to setup this feature." + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "安装方式不受支持。请使用SideStore或AltStore安装来使用此功能。" + } + } + } + }, + "lc.settings.warning" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Please Don't use LiveContainer for piracy." + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "请勿将LiveContainer用于盗版。" + } + } + } + }, + "lc.tabView.apps" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Apps" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "App" + } + } + } + }, + "lc.tabView.settings" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Settings" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "设置" + } + } + } + }, + "lc.tabView.tweaks" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tweaks" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "模块" + } + } + } + }, + "lc.tweakView.appFolderDesc" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "This is the app-specific folder. Set the tweak folder and the guest app will pick them up recursively." + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "这是App专用文件夹。将App的模块文件夹设置为本文件夹,则App在启动时会递归地加载。" + } + } + } + }, + "lc.tweakView.globalFolderDesc" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "This is the global folder. All tweaks put here will be injected to all guest apps. Create a new folder if you use app-specific tweaks." + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "这是全局文件夹,这里的全部模块会被加载到所有App中。要为App单独加载模块,请新建文件夹。" + } + } + } + }, + "lc.tweakView.importTweak" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Import Tweak" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "导入模块" + } + } + } + }, + "lc.tweakView.newFolder" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "New folder" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "新建文件夹" + } + } + } + }, + "lc.tweakView.notFileError %@" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ is not a file." + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@不是一个文件。" + } + } + } + }, + "lc.tweakView.permissionDeniedError %@" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cannot open %@, permission denied." + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "无法打开%@,权限不足。" + } + } + } + }, + "lc.utils.initSigningError" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Failed to initiate bundle signing." + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "初始化签名失败" + } + } + } + }, + "lc.utils.requireAuthentication" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Authentication Required." + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "需要授权。" + } + } + } + }, + "lc.webView.pageCanBeOpenIn %@" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "This web page can be opened in \"%@\", continue?" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "此页面可以在“%@”中打开,要继续吗?" + } + } + } + }, + "lc.webView.pageLaunch %@" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "This web page is trying to launch \"%@\", continue?" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "此页面想要打开“%@”,要继续吗?" + } + } + } + }, + "lc.webView.runApp" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Run App" + } + }, + "zh_CN" : { + "stringUnit" : { + "state" : "translated", + "value" : "启动App" + } + } + } + } + }, + "version" : "1.0" +} \ No newline at end of file diff --git a/LiveContainerSwiftUI/Shared.swift b/LiveContainerSwiftUI/Shared.swift index 61635a0..1575202 100644 --- a/LiveContainerSwiftUI/Shared.swift +++ b/LiveContainerSwiftUI/Shared.swift @@ -64,8 +64,35 @@ class DataManager { extension String: LocalizedError { public var errorDescription: String? { return self } + + private static var enBundle : Bundle? { + let language = "en" + let path = Bundle.main.path(forResource:language, ofType: "lproj") + let bundle = Bundle(path: path!) + return bundle + } + + var loc: String { + let message = NSLocalizedString(self, comment: "") + if message != self { + return message + } + + if let forcedString = String.enBundle?.localizedString(forKey: self, value: nil, table: nil){ + return forcedString + }else { + return self + } + } + + func localizeWithFormat(_ arguments: CVarArg...) -> String{ + String.localizedStringWithFormat(self.loc, arguments) + } + } + + extension UTType { static let ipa = UTType(filenameExtension: "ipa")! static let dylib = UTType(filenameExtension: "dylib")! @@ -134,11 +161,11 @@ public struct TextFieldAlertModifier: ViewModifier { $0.text = self.text.wrappedValue $0.clearButtonMode = .always } - controller.addAction(UIAlertAction(title: "Cancel", style: .cancel) { _ in + controller.addAction(UIAlertAction(title: "lc.common.cancel".loc, style: .cancel) { _ in self.actionCancel(nil) shutdown() }) - controller.addAction(UIAlertAction(title: "OK", style: .default) { _ in + controller.addAction(UIAlertAction(title: "lc.common.ok".loc, style: .default) { _ in self.action(controller.textFields?.first?.text) shutdown() }) @@ -260,7 +287,7 @@ extension LCUtils { c.resume() } guard let progress = progress else { - ans = "Failed to initiate bundle signing." + ans = "lc.utils.initSigningError".loc c.resume() return } @@ -298,7 +325,7 @@ extension LCUtils { // Check if the device supports biometric authentication if context.canEvaluatePolicy(.deviceOwnerAuthentication, error: &error) { // Determine the reason for the authentication request - let reason = "Authentication Required." + let reason = "lc.utils.requireAuthentication".loc // Evaluate the authentication policy context.evaluatePolicy(.deviceOwnerAuthentication, localizedReason: reason) { success, evaluationError in diff --git a/Makefile b/Makefile index 7764a7e..22f74d4 100644 --- a/Makefile +++ b/Makefile @@ -24,6 +24,7 @@ include $(THEOS_MAKE_PATH)/aggregate.mk # Make the executable name longer so we have space to overwrite it with the guest app's name before-package:: + @/Applications/Xcode.app/Contents/Developer/usr/bin/xcstringstool compile ./LiveContainerSwiftUI/Localizable.xcstrings --output-directory $(THEOS_STAGING_DIR)/Applications/LiveContainer.app @/Applications/Xcode.app/Contents/Developer/usr/bin/actool LiveContainerSwiftUI/Assets.xcassets --compile $(THEOS_STAGING_DIR)/Applications/LiveContainer.app --platform iphoneos --minimum-deployment-target 14.0 @cp $(THEOS_STAGING_DIR)/Applications/LiveContainer.app/LiveContainer $(THEOS_STAGING_DIR)/Applications/LiveContainer.app/JITLessSetup @ldid -Sentitlements_setup.xml $(THEOS_STAGING_DIR)/Applications/LiveContainer.app/JITLessSetup diff --git a/Resources/ar.lproj/InfoPlist.strings b/Resources/ar.lproj/InfoPlist.strings deleted file mode 100644 index 29e6f31..0000000 Binary files a/Resources/ar.lproj/InfoPlist.strings and /dev/null differ diff --git a/Resources/ca.lproj/InfoPlist.strings b/Resources/ca.lproj/InfoPlist.strings deleted file mode 100644 index 29e6f31..0000000 Binary files a/Resources/ca.lproj/InfoPlist.strings and /dev/null differ diff --git a/Resources/cs.lproj/InfoPlist.strings b/Resources/cs.lproj/InfoPlist.strings deleted file mode 100644 index 29e6f31..0000000 Binary files a/Resources/cs.lproj/InfoPlist.strings and /dev/null differ diff --git a/Resources/da.lproj/InfoPlist.strings b/Resources/da.lproj/InfoPlist.strings deleted file mode 100644 index 29e6f31..0000000 Binary files a/Resources/da.lproj/InfoPlist.strings and /dev/null differ diff --git a/Resources/de.lproj/InfoPlist.strings b/Resources/de.lproj/InfoPlist.strings deleted file mode 100644 index 29e6f31..0000000 Binary files a/Resources/de.lproj/InfoPlist.strings and /dev/null differ diff --git a/Resources/el.lproj/InfoPlist.strings b/Resources/el.lproj/InfoPlist.strings deleted file mode 100644 index 29e6f31..0000000 Binary files a/Resources/el.lproj/InfoPlist.strings and /dev/null differ diff --git a/Resources/en.lproj/InfoPlist.strings b/Resources/en.lproj/InfoPlist.strings deleted file mode 100644 index 29e6f31..0000000 Binary files a/Resources/en.lproj/InfoPlist.strings and /dev/null differ diff --git a/Resources/en_AU.lproj/InfoPlist.strings b/Resources/en_AU.lproj/InfoPlist.strings deleted file mode 100644 index 29e6f31..0000000 Binary files a/Resources/en_AU.lproj/InfoPlist.strings and /dev/null differ diff --git a/Resources/en_GB.lproj/InfoPlist.strings b/Resources/en_GB.lproj/InfoPlist.strings deleted file mode 100644 index 29e6f31..0000000 Binary files a/Resources/en_GB.lproj/InfoPlist.strings and /dev/null differ diff --git a/Resources/es.lproj/InfoPlist.strings b/Resources/es.lproj/InfoPlist.strings deleted file mode 100644 index 29e6f31..0000000 Binary files a/Resources/es.lproj/InfoPlist.strings and /dev/null differ diff --git a/Resources/es_419.lproj/InfoPlist.strings b/Resources/es_419.lproj/InfoPlist.strings deleted file mode 100644 index 29e6f31..0000000 Binary files a/Resources/es_419.lproj/InfoPlist.strings and /dev/null differ diff --git a/Resources/fi.lproj/InfoPlist.strings b/Resources/fi.lproj/InfoPlist.strings deleted file mode 100644 index 29e6f31..0000000 Binary files a/Resources/fi.lproj/InfoPlist.strings and /dev/null differ diff --git a/Resources/fr.lproj/InfoPlist.strings b/Resources/fr.lproj/InfoPlist.strings deleted file mode 100644 index 29e6f31..0000000 Binary files a/Resources/fr.lproj/InfoPlist.strings and /dev/null differ diff --git a/Resources/fr_CA.lproj/InfoPlist.strings b/Resources/fr_CA.lproj/InfoPlist.strings deleted file mode 100644 index 29e6f31..0000000 Binary files a/Resources/fr_CA.lproj/InfoPlist.strings and /dev/null differ diff --git a/Resources/he.lproj/InfoPlist.strings b/Resources/he.lproj/InfoPlist.strings deleted file mode 100644 index 29e6f31..0000000 Binary files a/Resources/he.lproj/InfoPlist.strings and /dev/null differ diff --git a/Resources/hi.lproj/InfoPlist.strings b/Resources/hi.lproj/InfoPlist.strings deleted file mode 100644 index 29e6f31..0000000 Binary files a/Resources/hi.lproj/InfoPlist.strings and /dev/null differ diff --git a/Resources/hr.lproj/InfoPlist.strings b/Resources/hr.lproj/InfoPlist.strings deleted file mode 100644 index 29e6f31..0000000 Binary files a/Resources/hr.lproj/InfoPlist.strings and /dev/null differ diff --git a/Resources/hu.lproj/InfoPlist.strings b/Resources/hu.lproj/InfoPlist.strings deleted file mode 100644 index 29e6f31..0000000 Binary files a/Resources/hu.lproj/InfoPlist.strings and /dev/null differ diff --git a/Resources/id.lproj/InfoPlist.strings b/Resources/id.lproj/InfoPlist.strings deleted file mode 100644 index 29e6f31..0000000 Binary files a/Resources/id.lproj/InfoPlist.strings and /dev/null differ diff --git a/Resources/it.lproj/InfoPlist.strings b/Resources/it.lproj/InfoPlist.strings deleted file mode 100644 index 29e6f31..0000000 Binary files a/Resources/it.lproj/InfoPlist.strings and /dev/null differ diff --git a/Resources/ja.lproj/InfoPlist.strings b/Resources/ja.lproj/InfoPlist.strings deleted file mode 100644 index 29e6f31..0000000 Binary files a/Resources/ja.lproj/InfoPlist.strings and /dev/null differ diff --git a/Resources/ko.lproj/InfoPlist.strings b/Resources/ko.lproj/InfoPlist.strings deleted file mode 100644 index 29e6f31..0000000 Binary files a/Resources/ko.lproj/InfoPlist.strings and /dev/null differ diff --git a/Resources/ms.lproj/InfoPlist.strings b/Resources/ms.lproj/InfoPlist.strings deleted file mode 100644 index 29e6f31..0000000 Binary files a/Resources/ms.lproj/InfoPlist.strings and /dev/null differ diff --git a/Resources/nl.lproj/InfoPlist.strings b/Resources/nl.lproj/InfoPlist.strings deleted file mode 100644 index 29e6f31..0000000 Binary files a/Resources/nl.lproj/InfoPlist.strings and /dev/null differ diff --git a/Resources/no.lproj/InfoPlist.strings b/Resources/no.lproj/InfoPlist.strings deleted file mode 100644 index 29e6f31..0000000 Binary files a/Resources/no.lproj/InfoPlist.strings and /dev/null differ diff --git a/Resources/pl.lproj/InfoPlist.strings b/Resources/pl.lproj/InfoPlist.strings deleted file mode 100644 index 29e6f31..0000000 Binary files a/Resources/pl.lproj/InfoPlist.strings and /dev/null differ diff --git a/Resources/pt_BR.lproj/InfoPlist.strings b/Resources/pt_BR.lproj/InfoPlist.strings deleted file mode 100644 index 29e6f31..0000000 Binary files a/Resources/pt_BR.lproj/InfoPlist.strings and /dev/null differ diff --git a/Resources/pt_PT.lproj/InfoPlist.strings b/Resources/pt_PT.lproj/InfoPlist.strings deleted file mode 100644 index 29e6f31..0000000 Binary files a/Resources/pt_PT.lproj/InfoPlist.strings and /dev/null differ diff --git a/Resources/ro.lproj/InfoPlist.strings b/Resources/ro.lproj/InfoPlist.strings deleted file mode 100644 index 29e6f31..0000000 Binary files a/Resources/ro.lproj/InfoPlist.strings and /dev/null differ diff --git a/Resources/ru.lproj/InfoPlist.strings b/Resources/ru.lproj/InfoPlist.strings deleted file mode 100644 index 29e6f31..0000000 Binary files a/Resources/ru.lproj/InfoPlist.strings and /dev/null differ diff --git a/Resources/sk.lproj/InfoPlist.strings b/Resources/sk.lproj/InfoPlist.strings deleted file mode 100644 index 29e6f31..0000000 Binary files a/Resources/sk.lproj/InfoPlist.strings and /dev/null differ diff --git a/Resources/sv.lproj/InfoPlist.strings b/Resources/sv.lproj/InfoPlist.strings deleted file mode 100644 index 29e6f31..0000000 Binary files a/Resources/sv.lproj/InfoPlist.strings and /dev/null differ diff --git a/Resources/th.lproj/InfoPlist.strings b/Resources/th.lproj/InfoPlist.strings deleted file mode 100644 index 29e6f31..0000000 Binary files a/Resources/th.lproj/InfoPlist.strings and /dev/null differ diff --git a/Resources/tr.lproj/InfoPlist.strings b/Resources/tr.lproj/InfoPlist.strings deleted file mode 100644 index 29e6f31..0000000 Binary files a/Resources/tr.lproj/InfoPlist.strings and /dev/null differ diff --git a/Resources/uk.lproj/InfoPlist.strings b/Resources/uk.lproj/InfoPlist.strings deleted file mode 100644 index 29e6f31..0000000 Binary files a/Resources/uk.lproj/InfoPlist.strings and /dev/null differ diff --git a/Resources/vi.lproj/InfoPlist.strings b/Resources/vi.lproj/InfoPlist.strings deleted file mode 100644 index 29e6f31..0000000 Binary files a/Resources/vi.lproj/InfoPlist.strings and /dev/null differ diff --git a/Resources/zh_CN.lproj/InfoPlist.strings b/Resources/zh_CN.lproj/InfoPlist.strings deleted file mode 100644 index 29e6f31..0000000 Binary files a/Resources/zh_CN.lproj/InfoPlist.strings and /dev/null differ diff --git a/Resources/zh_HK.lproj/InfoPlist.strings b/Resources/zh_HK.lproj/InfoPlist.strings deleted file mode 100644 index 29e6f31..0000000 Binary files a/Resources/zh_HK.lproj/InfoPlist.strings and /dev/null differ diff --git a/Resources/zh_TW.lproj/InfoPlist.strings b/Resources/zh_TW.lproj/InfoPlist.strings deleted file mode 100644 index 29e6f31..0000000 Binary files a/Resources/zh_TW.lproj/InfoPlist.strings and /dev/null differ