diff --git a/OSXChatGPT/OSXChatGPT.xcodeproj/project.pbxproj b/OSXChatGPT/OSXChatGPT.xcodeproj/project.pbxproj index 08b1303..80ea16e 100644 --- a/OSXChatGPT/OSXChatGPT.xcodeproj/project.pbxproj +++ b/OSXChatGPT/OSXChatGPT.xcodeproj/project.pbxproj @@ -69,6 +69,8 @@ CB2F972029CE1ADC004EBD96 /* OSXChatGPT.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = CBC4B0FD29B8BF9600650296 /* OSXChatGPT.xcdatamodeld */; }; CB2F972229CED6AE004EBD96 /* ChatRoomInputView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB2F972129CED6AE004EBD96 /* ChatRoomInputView.swift */; }; CB2F972829CEFB65004EBD96 /* ChatRoomToolBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB2F972729CEFB65004EBD96 /* ChatRoomToolBar.swift */; }; + CB373A9B29F56CFF00B8D9BE /* Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB373A9A29F56CFF00B8D9BE /* Localization.swift */; }; + CB4D1FC429F195E60010D063 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = CB4D1FC629F195E60010D063 /* Localizable.strings */; }; CB53A3BE29D48C8F00A5B8FC /* Prompt+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB53A3BC29D48C8F00A5B8FC /* Prompt+CoreDataClass.swift */; }; CB53A3BF29D48C8F00A5B8FC /* Prompt+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB53A3BD29D48C8F00A5B8FC /* Prompt+CoreDataProperties.swift */; }; CBD5AB6429E6DE9A007B6625 /* ProjectSettingManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBD5AB6329E6DE9A007B6625 /* ProjectSettingManager.swift */; }; @@ -138,6 +140,9 @@ CB2D438829F0183A007742AE /* ChatGPT+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ChatGPT+CoreDataProperties.swift"; sourceTree = ""; }; CB2F972129CED6AE004EBD96 /* ChatRoomInputView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatRoomInputView.swift; sourceTree = ""; }; CB2F972729CEFB65004EBD96 /* ChatRoomToolBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatRoomToolBar.swift; sourceTree = ""; }; + CB373A9A29F56CFF00B8D9BE /* Localization.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Localization.swift; sourceTree = ""; }; + CB4D1FC529F195E60010D063 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; + CB4D1FC729F195EA0010D063 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = ""; }; CB53A3BC29D48C8F00A5B8FC /* Prompt+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Prompt+CoreDataClass.swift"; sourceTree = ""; }; CB53A3BD29D48C8F00A5B8FC /* Prompt+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Prompt+CoreDataProperties.swift"; sourceTree = ""; }; CBC4B0FE29B8BF9600650296 /* OSXChatGPT.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = OSXChatGPT.xcdatamodel; sourceTree = ""; }; @@ -214,6 +219,7 @@ 182B437129BC5D1B00F06778 /* ChatGPTManager.swift */, 182B436F29BC5D1B00F06778 /* CoreDataManager.swift */, 182B437029BC5D1B00F06778 /* ViewModel.swift */, + CB373A9A29F56CFF00B8D9BE /* Localization.swift */, CBD5AB6329E6DE9A007B6625 /* ProjectSettingManager.swift */, CB28A52129C07BE500F0286A /* KeyboardMonitor.swift */, CB27657229D30F1400897E0E /* AIPromptViewMdoel.swift */, @@ -261,6 +267,7 @@ CBC4B11429B8CB1B00650296 /* Models */, 182B42B529BBA82800F06778 /* Storyboard.storyboard */, CBC4B0FD29B8BF9600650296 /* OSXChatGPT.xcdatamodeld */, + CB4D1FC629F195E60010D063 /* Localizable.strings */, CB1DCAC529B4F09F00B1D4E1 /* Assets.xcassets */, CB1DCACA29B4F09F00B1D4E1 /* OSXChatGPT.entitlements */, CB1DCAC729B4F09F00B1D4E1 /* Preview Content */, @@ -418,6 +425,7 @@ knownRegions = ( en, Base, + "zh-Hans", ); mainGroup = CB1DCAB529B4F09D00B1D4E1; packageReferences = ( @@ -440,6 +448,7 @@ buildActionMask = 2147483647; files = ( CB1DCAC929B4F09F00B1D4E1 /* Preview Assets.xcassets in Resources */, + CB4D1FC429F195E60010D063 /* Localizable.strings in Resources */, CB1DCAC629B4F09F00B1D4E1 /* Assets.xcassets in Resources */, 182B42B629BBA82800F06778 /* Storyboard.storyboard in Resources */, ); @@ -454,6 +463,7 @@ files = ( CB1F012F29E999EF009CF942 /* Segment.swift in Sources */, CB1F015C29EAFBF5009CF942 /* MessageText+CoreDataProperties.swift in Sources */, + CB373A9B29F56CFF00B8D9BE /* Localization.swift in Sources */, CB1F015129E9BC8C009CF942 /* Tokenizer.swift in Sources */, CB2449FA29D7FE38006EE829 /* ServerManager.swift in Sources */, CB1F014829E99B5E009CF942 /* Int+IsOdd.swift in Sources */, @@ -518,6 +528,18 @@ }; /* End PBXSourcesBuildPhase section */ +/* Begin PBXVariantGroup section */ + CB4D1FC629F195E60010D063 /* Localizable.strings */ = { + isa = PBXVariantGroup; + children = ( + CB4D1FC529F195E60010D063 /* en */, + CB4D1FC729F195EA0010D063 /* zh-Hans */, + ); + name = Localizable.strings; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + /* Begin XCBuildConfiguration section */ CB1DCACB29B4F09F00B1D4E1 /* Debug */ = { isa = XCBuildConfiguration; diff --git a/OSXChatGPT/OSXChatGPT/DataProvider/ChatGPTManager.swift b/OSXChatGPT/OSXChatGPT/DataProvider/ChatGPTManager.swift index b674284..bf81854 100644 --- a/OSXChatGPT/OSXChatGPT/DataProvider/ChatGPTManager.swift +++ b/OSXChatGPT/OSXChatGPT/DataProvider/ChatGPTManager.swift @@ -103,9 +103,9 @@ enum ChatGPTAnswerType: CaseIterable, ToolBarMenuProtocol { var value: String { switch self { case .stream: - return "流式" + return Localization.AnswerStream.localized case .oneTime: - return "单式" + return Localization.AnswerOneTime.localized } } case stream diff --git a/OSXChatGPT/OSXChatGPT/DataProvider/Localization.swift b/OSXChatGPT/OSXChatGPT/DataProvider/Localization.swift new file mode 100644 index 0000000..3b2d634 --- /dev/null +++ b/OSXChatGPT/OSXChatGPT/DataProvider/Localization.swift @@ -0,0 +1,180 @@ +// +// Localization.swift +// OSXChatGPT +// +// Created by CoderChan on 2023/4/23. +// + +import Foundation +import SwiftUI + + +enum Localization { + case newChat + case prompt(_ text: String) + case editRemark + case deleteSession + case EditConversationRemark + case EnterRemark + case fasterResponse + case PromptLibrary + case NoLoginRequired + case NoMonthlyFee + case BetterApplication + case adMovie + case adWebsite + case UpdateAPIKey + case EnterAPIKey + case EnterYourAPIKey + case YouNeedApiKey + case GetYourAPIKey + case Cancel + case Save + case TheAppWillConnectOpenAIServer + case deleteMessage + case copyMessage + case ParameterAdjustment + case TemperatureT(_ text: String) + case ModelT(_ text: String) + case ContextT(_ text: String) + case Answer + case Prompts + case ClearMessage + case StopAnswer + case Empty + case CurrentTemperature + case RemoveShortcuts + case AddShortcuts + case DeleteData + case PleaseClickUpperRightAddCustomPrompt + case SelectPrompt + case Confirm + case Library + case DefaultNoPrompt + case CurrentSelectPrompt + case NoPromptToLibraryAdd + case SelectOnlyOnePromptPerSession + case CustomAdd + case Title + case Required + case Author + case ShareYourPromptToLibrary + case ShareOrNot + case AnswerStream + case AnswerOneTime + + var localized: String { + switch self { + case .newChat: + return String(format: NSLocalizedString("newChat", comment: "")) + case .prompt(let t): + return String(format: NSLocalizedString("Prompt", comment: ""), t) + case .editRemark: + return String(format: NSLocalizedString("editRemark", comment: "")) + case .deleteSession: + return String(format: NSLocalizedString("deleteSession", comment: "")) + case .EditConversationRemark: + return String(format: NSLocalizedString("EditConversationRemark", comment: "")) + case .EnterRemark: + return String(format: NSLocalizedString("EnterRemark", comment: "")) + case .fasterResponse: + return String(format: NSLocalizedString("FasterResponse", comment: "")) + case .PromptLibrary: + return String(format: NSLocalizedString("PromptLibrary", comment: "")) + case .NoLoginRequired: + return String(format: NSLocalizedString("NoLoginRequired", comment: "")) + case .NoMonthlyFee: + return String(format: NSLocalizedString("NoMonthlyFee", comment: "")) + case .BetterApplication: + return String(format: NSLocalizedString("BetterApplication", comment: "")) + case .adMovie: + return String(format: NSLocalizedString("adMovie", comment: "")) + case .adWebsite: + return String(format: NSLocalizedString("adWebsite", comment: "")) + case .UpdateAPIKey: + return String(format: NSLocalizedString("UpdateAPIKey", comment: "")) + case .EnterAPIKey: + return String(format: NSLocalizedString("EnterAPIKey", comment: "")) + case .EnterYourAPIKey: + return String(format: NSLocalizedString("EnterYourAPIKey", comment: "")) + case .YouNeedApiKey: + return String(format: NSLocalizedString("YouNeedApiKey", comment: "")) + case .GetYourAPIKey: + return String(format: NSLocalizedString("GetYourAPIKey", comment: "")) + case .Cancel: + return String(format: NSLocalizedString("Cancel", comment: "")) + case .Save: + return String(format: NSLocalizedString("Save", comment: "")) + case .TheAppWillConnectOpenAIServer: + return String(format: NSLocalizedString("TheAppWillConnectOpenAIServer", comment: "")) + case .deleteMessage: + return String(format: NSLocalizedString("deleteMessage", comment: "")) + case .copyMessage: + return String(format: NSLocalizedString("copyMessage", comment: "")) + case .ParameterAdjustment: + return String(format: NSLocalizedString("ParameterAdjustment", comment: "")) + case .TemperatureT(let t): + return String(format: NSLocalizedString("TemperatureT", comment: ""), t) + case .ModelT(let t): + return String(format: NSLocalizedString("ModelT", comment: ""), t) + case .ContextT(let t): + return String(format: NSLocalizedString("ContextT", comment: ""), t) + case .Answer: + return String(format: NSLocalizedString("Answer", comment: "")) + case .Prompts: + return String(format: NSLocalizedString("Prompts", comment: "")) + case .ClearMessage: + return String(format: NSLocalizedString("ClearMessage", comment: "")) + case .StopAnswer: + return String(format: NSLocalizedString("StopAnswer", comment: "")) + case .Empty: + return String(format: NSLocalizedString("Empty", comment: "")) + case .CurrentTemperature: + return String(format: NSLocalizedString("CurrentTemperature", comment: "")) + case .RemoveShortcuts: + return String(format: NSLocalizedString("RemoveShortcuts", comment: "")) + case .AddShortcuts: + return String(format: NSLocalizedString("AddShortcuts", comment: "")) + case .DeleteData: + return String(format: NSLocalizedString("DeleteData", comment: "")) + case .PleaseClickUpperRightAddCustomPrompt: + return String(format: NSLocalizedString("PleaseClickUpperRightAddCustomPrompt", comment: "")) + case .SelectPrompt: + return String(format: NSLocalizedString("SelectPrompt", comment: "")) + case .Confirm: + return String(format: NSLocalizedString("Confirm", comment: "")) + case .Library: + return String(format: NSLocalizedString("Library", comment: "")) + case .DefaultNoPrompt: + return String(format: NSLocalizedString("DefaultNoPrompt", comment: "")) + case .CurrentSelectPrompt: + return String(format: NSLocalizedString("CurrentSelectPrompt", comment: "")) + case .NoPromptToLibraryAdd: + return String(format: NSLocalizedString("NoPromptToLibraryAdd", comment: "")) + case .SelectOnlyOnePromptPerSession: + return String(format: NSLocalizedString("SelectOnlyOnePromptPerSession", comment: "")) + case .CustomAdd: + return String(format: NSLocalizedString("CustomAdd", comment: "")) + case .Title: + return String(format: NSLocalizedString("Title", comment: "")) + case .Required: + return String(format: NSLocalizedString("Required", comment: "")) + case .Author: + return String(format: NSLocalizedString("Author", comment: "")) + case .ShareYourPromptToLibrary: + return String(format: NSLocalizedString("ShareYourPromptToLibrary", comment: "")) + case .ShareOrNot: + return String(format: NSLocalizedString("ShareOrNot", comment: "")) + case .AnswerStream: + return String(format: NSLocalizedString("AnswerStream", comment: "")) + case .AnswerOneTime: + return String(format: NSLocalizedString("AnswerOneTime", comment: "")) + } + + } + +} + + + + diff --git a/OSXChatGPT/OSXChatGPT/DataProvider/ViewModel.swift b/OSXChatGPT/OSXChatGPT/DataProvider/ViewModel.swift index d3789dc..f7840cf 100644 --- a/OSXChatGPT/OSXChatGPT/DataProvider/ViewModel.swift +++ b/OSXChatGPT/OSXChatGPT/DataProvider/ViewModel.swift @@ -311,6 +311,7 @@ extension ViewModel { if ChatGPTManager.shared.answerType.valueBool { self.showStopAnswerBtn = true } + var stream: String = "" ChatGPTManager.shared.askChatGPTStream(messages: messages, prompt: prompt, chatGpt: currentConversation?.chatGPT) { rsp in if rsp.request.answerType == .stream { @@ -417,9 +418,8 @@ extension ViewModel { self.messages.append(newMsg!) } } - newMsg?.text = rsp.text - //失败 CoreDataManager.shared.saveData() + //失败 newMsg?.text = rsp.text if self.currentConversation?.sesstionId == sesstionId { if self.messages.count > 0 { diff --git a/OSXChatGPT/OSXChatGPT/WindowView/AIPromptInputView.swift b/OSXChatGPT/OSXChatGPT/WindowView/AIPromptInputView.swift index 7d237b6..53fbbc0 100644 --- a/OSXChatGPT/OSXChatGPT/WindowView/AIPromptInputView.swift +++ b/OSXChatGPT/OSXChatGPT/WindowView/AIPromptInputView.swift @@ -22,7 +22,7 @@ struct AIPromptInputView: View { VStack { VStack { Spacer() - Text("自定义添加") + Text(Localization.CustomAdd.localized) .font(.title3) .foregroundColor((colorScheme == .dark) ? .white.opacity(0.9) :.black.opacity(0.9)) Spacer() @@ -32,13 +32,13 @@ struct AIPromptInputView: View { VStack { HStack { - Text("标题") + Text(Localization.Title.localized) .font(.title3) .padding(.top, 5) .padding(.leading, 20) .padding(.bottom, 0) .frame(height: 18) - Text("*必填") + Text(Localization.Required.localized) .font(Font.system(size: 11)) .padding(.top, 5) .foregroundColor(.gray.opacity(0.6)) @@ -58,13 +58,13 @@ struct AIPromptInputView: View { .padding(.trailing, 20) HStack { - Text("修饰语") + Text(Localization.Prompts.localized) .font(.title3) .padding(.top, 5) .padding(.leading, 20) .padding(.bottom, 0) .frame(height: 18) - Text("*必填") + Text(Localization.Required.localized) .font(Font.system(size: 11)) .padding(.top, 5) .foregroundColor(.gray.opacity(0.6)) @@ -84,7 +84,7 @@ struct AIPromptInputView: View { .padding(.trailing, 20) HStack { - Text("作者") + Text(Localization.Author.localized) .font(.title3) .padding(.top, 5) .padding(.leading, 20) @@ -95,7 +95,7 @@ struct AIPromptInputView: View { // .padding(.top, 5) // .foregroundColor(.gray.opacity(0.6)) // .frame(height: 18) - Text("分享您的修饰语到词库") + Text(Localization.ShareYourPromptToLibrary.localized) .font(Font.system(size: 10)) .padding(.top, 5) .foregroundColor(.gray.opacity(0.6)) @@ -119,7 +119,7 @@ struct AIPromptInputView: View { VStack { HStack { - Toggle("是否分享", isOn: $isToggleOn) + Toggle(Localization.ShareOrNot.localized, isOn: $isToggleOn) .padding() .foregroundColor(.gray) .font(Font.system(size: 13)) @@ -128,7 +128,7 @@ struct AIPromptInputView: View { Button { self.isPresented = false } label: { - Text("取消") + Text(Localization.Cancel.localized) } Button { @@ -140,7 +140,7 @@ struct AIPromptInputView: View { self.isPresented = false } label: { - Text("确定") + Text(Localization.Confirm.localized) } .padding(.trailing, 20) diff --git a/OSXChatGPT/OSXChatGPT/WindowView/AIPromptPopView.swift b/OSXChatGPT/OSXChatGPT/WindowView/AIPromptPopView.swift index 843c129..8d1e9d6 100644 --- a/OSXChatGPT/OSXChatGPT/WindowView/AIPromptPopView.swift +++ b/OSXChatGPT/OSXChatGPT/WindowView/AIPromptPopView.swift @@ -28,7 +28,7 @@ struct AIPromptPopView: View { ZStack { VStack { Spacer() - Text("选择提示") + Text(Localization.SelectPrompt.localized) .font(.title3) .foregroundColor(titleColor) Spacer() @@ -41,7 +41,7 @@ struct AIPromptPopView: View { } self.showPopover = false } label: { - Text("确定") + Text(Localization.Confirm.localized) }.padding(10) Spacer() Button { @@ -51,7 +51,7 @@ struct AIPromptPopView: View { viewModel.showAIPrompt = true } } label: { - Text("词库") + Text(Localization.Library.localized) } .padding(10) } @@ -67,7 +67,7 @@ struct AIPromptPopView: View { data.deletePrompt(prompt: item) } }) { - Text("移除快捷方式") + Text(Localization.RemoveShortcuts.localized) } } }.frame(width: 560, height: 380) @@ -104,22 +104,22 @@ struct AIPromptPopCellView: View { if item.promptType == .hint { VStack(alignment: .leading, spacing: 4) { HStack { - Text("【默认无修饰语】") + Text(Localization.DefaultNoPrompt.localized) .font(Font.system(size: 15)) .foregroundColor((colorScheme == .dark) ? .white.opacity(0.8) : .white) .padding(.trailing, 6) .padding(.bottom, 6) - Text("当前选中的修饰语") + Text(Localization.CurrentSelectPrompt.localized) .font(Font.system(size: 14)) .foregroundColor((colorScheme == .dark) ? .white.opacity(0.8) : .white) .padding(.bottom, 6) Spacer() - Text("(没有修饰语请到词库添加)") + Text(Localization.NoPromptToLibraryAdd.localized) .font(Font.system(size: 11)) .foregroundColor((colorScheme == .dark) ? .white.opacity(0.8) : .white) .padding(.bottom, 6) } - Text("每个会话只能选择一个修饰语, 也可以自定义添加修饰语") + Text(Localization.SelectOnlyOnePromptPerSession.localized) .font(.subheadline) .foregroundColor((colorScheme == .dark) ? .white.opacity(0.6) : .white) }.padding(.leading, 2) diff --git a/OSXChatGPT/OSXChatGPT/WindowView/AIPromptView.swift b/OSXChatGPT/OSXChatGPT/WindowView/AIPromptView.swift index 801abb4..ead4c93 100644 --- a/OSXChatGPT/OSXChatGPT/WindowView/AIPromptView.swift +++ b/OSXChatGPT/OSXChatGPT/WindowView/AIPromptView.swift @@ -43,7 +43,7 @@ struct AIPromptDetailView: View { .frame(width: 10, height: 10) .foregroundColor(.white) .padding(0) - Text("移除快捷方式") + Text(Localization.RemoveShortcuts.localized) .padding(0) .foregroundColor(.white) }else { @@ -53,7 +53,7 @@ struct AIPromptDetailView: View { .frame(width: 10, height: 10) .foregroundColor(.white) .padding(0) - Text("添加快捷方式") + Text(Localization.AddShortcuts.localized) .padding(0) .foregroundColor(.white) } @@ -78,7 +78,7 @@ struct AIPromptDetailView: View { .frame(width: 10, height: 10) .foregroundColor(.white) .padding(0) - Text("删除数据") + Text(Localization.DeleteData.localized) .padding(0) .foregroundColor(.white) } @@ -176,7 +176,7 @@ struct AIPromptView: View { } }else { VStack(alignment: .center) { - Text("请点击右上角自定义添加新的修饰语") + Text(Localization.PleaseClickUpperRightAddCustomPrompt.localized) }.frame(width: geometry.size.width, height: geometry.size.height - 50) } diff --git a/OSXChatGPT/OSXChatGPT/WindowView/ChatRoomToolBar.swift b/OSXChatGPT/OSXChatGPT/WindowView/ChatRoomToolBar.swift index bb66a2b..00afad8 100644 --- a/OSXChatGPT/OSXChatGPT/WindowView/ChatRoomToolBar.swift +++ b/OSXChatGPT/OSXChatGPT/WindowView/ChatRoomToolBar.swift @@ -19,13 +19,13 @@ struct ChatRoomToolBar: View { @State private var isAnswerTypeTrue = ChatGPTManager.shared.answerType.valueBool var body: some View { HStack { - MenuButton("参数调节") { - Button("温度调节(\(temperature))") { + MenuButton(Localization.ParameterAdjustment.localized) { + Button(Localization.TemperatureT(temperature).localized) { showDragView.toggle() } .padding(.leading, 0) - BrowserView(items: ChatGPTModel.allCases, title: "模型(\(model))", item: viewModel.currentConversation?.chatGPT?.modelType ?? .gpt35turbo) { model in + BrowserView(items: ChatGPTModel.allCases, title: Localization.ModelT(model).localized, item: viewModel.currentConversation?.chatGPT?.modelType ?? .gpt35turbo) { model in viewModel.currentConversation?.chatGPT?.modelType = model viewModel.updateConversation(sesstion: viewModel.currentConversation) self.model = model.value @@ -33,7 +33,7 @@ struct ChatRoomToolBar: View { .padding(.leading, 0) .frame(width: 100) - BrowserView(items: ChatGPTContext.allCases, title: "上下文(\(context)组对话)", item: viewModel.currentConversation?.chatGPT?.context ?? .context3) { model in + BrowserView(items: ChatGPTContext.allCases, title: Localization.ContextT(context).localized, item: viewModel.currentConversation?.chatGPT?.context ?? .context3) { model in viewModel.currentConversation?.chatGPT?.context = model viewModel.updateConversation(sesstion: viewModel.currentConversation) context = model.value @@ -43,18 +43,18 @@ struct ChatRoomToolBar: View { } .padding(.leading, 0) - .frame(width: 85) + .frame(width: (Locale.current.languageCode == "zh") ? 85 : 95) .popover(isPresented: $showDragView, arrowEdge: .top) { TemperatureSliderView(temperature: $temperature).environmentObject(viewModel) } - BrowserView(items: ChatGPTAnswerType.allCases, title: "应答", item: ChatGPTManager.shared.answerType) { model in + BrowserView(items: ChatGPTAnswerType.allCases, title: Localization.Answer.localized, item: ChatGPTManager.shared.answerType) { model in ChatGPTManager.shared.answerType = model } - .frame(width: 60) + .frame(width: (Locale.current.languageCode == "zh") ? 60 : 77) - Button("修饰语") { + Button(Localization.Prompts.localized) { showPopover.toggle() } .popover(isPresented: $showPopover) { @@ -62,7 +62,7 @@ struct ChatRoomToolBar: View { } - Button("清空消息") { + Button(Localization.ClearMessage.localized) { viewModel.messages.removeAll() viewModel.deleteAllMessage(sesstionId: viewModel.currentConversation?.sesstionId ?? "") viewModel.updateConversation(sesstionId: viewModel.currentConversation?.sesstionId ?? "", message: nil) @@ -70,7 +70,7 @@ struct ChatRoomToolBar: View { Spacer() if viewModel.showStopAnswerBtn { - Button("停止生成") { + Button(Localization.StopAnswer.localized) { viewModel.cancel() DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { viewModel.showStopAnswerBtn = false @@ -88,11 +88,11 @@ struct ChatRoomToolBar: View { .onAppear { - let formattedValue = viewModel.currentConversation?.chatGPT?.temperatureValue ?? "空" + let formattedValue = viewModel.currentConversation?.chatGPT?.temperatureValue ?? Localization.Empty.localized self.temperature = formattedValue - self.model = viewModel.currentConversation?.chatGPT?.modelType.value ?? "空" - self.context = viewModel.currentConversation?.chatGPT?.context.value ?? "空" + self.model = viewModel.currentConversation?.chatGPT?.modelType.value ?? Localization.Empty.localized + self.context = viewModel.currentConversation?.chatGPT?.context.value ?? Localization.Empty.localized } } @@ -143,7 +143,7 @@ struct TemperatureSliderView: View { var body: some View { VStack { HStack { - Text("当前温度:") + Text(Localization.CurrentTemperature.localized) Text(change) .frame(width: 30) } diff --git a/OSXChatGPT/OSXChatGPT/WindowView/ChatRoomView.swift b/OSXChatGPT/OSXChatGPT/WindowView/ChatRoomView.swift index 11993b8..b789f59 100644 --- a/OSXChatGPT/OSXChatGPT/WindowView/ChatRoomView.swift +++ b/OSXChatGPT/OSXChatGPT/WindowView/ChatRoomView.swift @@ -157,7 +157,7 @@ struct ChatRoomCellView: View { Button(action: { viewModel.deleteMessage(message: message) }) { - Text("删除消息") + Text(Localization.deleteMessage.localized) } } @@ -198,13 +198,13 @@ struct ChatRoomCellView: View { Button(action: { viewModel.deleteMessage(message: message) }) { - Text("删除消息") + Text(Localization.deleteMessage.localized) } Button(action: { NSPasteboard.general.prepareForNewContents() NSPasteboard.general.setString(message.text ?? "", forType: .string) }) { - Text("复制消息") + Text(Localization.copyMessage.localized) } } if message.msgType == .fialMsg && viewModel.messages.last?.id == message.id { diff --git a/OSXChatGPT/OSXChatGPT/WindowView/EidtSessionRemarkView.swift b/OSXChatGPT/OSXChatGPT/WindowView/EidtSessionRemarkView.swift index 132d76f..b5413ff 100644 --- a/OSXChatGPT/OSXChatGPT/WindowView/EidtSessionRemarkView.swift +++ b/OSXChatGPT/OSXChatGPT/WindowView/EidtSessionRemarkView.swift @@ -13,13 +13,13 @@ struct EidtSessionRemarkView: View { @EnvironmentObject var viewModel: ViewModel var body: some View { VStack(spacing: 20) { - Text("Edit Conversation Remark:") + Text(Localization.EditConversationRemark.localized) .font(.title3) .fontWeight(.bold) .frame(maxWidth: .infinity, alignment: .center) .padding(.top, 20) - TextField("Enter remark", text: $remark) + TextField(Localization.EnterRemark.localized, text: $remark) .textFieldStyle(RoundedBorderTextFieldStyle()) .frame(width: 200, height: 50) @@ -27,7 +27,7 @@ struct EidtSessionRemarkView: View { Button(action: { self.presentationMode.wrappedValue.dismiss() }) { - Text("Cancel") + Text(Localization.Cancel.localized) .foregroundColor(.white) .padding(.vertical, 8) .padding(.horizontal, 20) @@ -43,7 +43,7 @@ struct EidtSessionRemarkView: View { self.presentationMode.wrappedValue.dismiss() }) { - Text("Save") + Text(Localization.Save.localized) .foregroundColor(.white) .padding(.vertical, 8) .padding(.horizontal, 20) diff --git a/OSXChatGPT/OSXChatGPT/WindowView/EnterAPIView.swift b/OSXChatGPT/OSXChatGPT/WindowView/EnterAPIView.swift index 6cea01a..2c2227a 100644 --- a/OSXChatGPT/OSXChatGPT/WindowView/EnterAPIView.swift +++ b/OSXChatGPT/OSXChatGPT/WindowView/EnterAPIView.swift @@ -14,13 +14,13 @@ struct EnterAPIView: View { var body: some View { VStack(spacing: 20) { - Text("Enter Your OpenAI API Key:") + Text(Localization.EnterYourAPIKey.localized) .font(.title) .fontWeight(.bold) .frame(maxWidth: .infinity, alignment: .center) .padding(.top, 20) - Text("You need a working OpenAI Api Key in order to use OSXChatGPT") + Text(Localization.YouNeedApiKey.localized) .foregroundColor(.gray) .frame(maxWidth: .infinity, alignment: .center) .padding(.horizontal, 20) @@ -30,14 +30,14 @@ struct EnterAPIView: View { NSWorkspace.shared.open(url) } }) { - Text("🌏 Get your API key from Open AI dashboard") + Text(Localization.GetYourAPIKey.localized) .foregroundColor(.blue) .frame(maxWidth: .infinity, alignment: .center) .padding(.horizontal, 20) } .buttonStyle(BorderlessButtonStyle())//删除背景色 - TextField("Enter your API key", text: $p_apiKey) + TextField(Localization.EnterYourAPIKey.localized, text: $p_apiKey) .textFieldStyle(RoundedBorderTextFieldStyle()) .frame(width: 400, height: 50) @@ -45,7 +45,7 @@ struct EnterAPIView: View { Button(action: { self.presentationMode.wrappedValue.dismiss() }) { - Text("Cancel") + Text(Localization.Cancel.localized) .foregroundColor(.white) .padding(.vertical, 8) .padding(.horizontal, 20) @@ -61,7 +61,7 @@ struct EnterAPIView: View { self.presentationMode.wrappedValue.dismiss() }) { - Text("Save") + Text(Localization.Save.localized) .foregroundColor(.white) .padding(.vertical, 8) .padding(.horizontal, 20) @@ -74,7 +74,7 @@ struct EnterAPIView: View { .frame(maxWidth: .infinity, alignment: .center) .padding(.top, 0) - Text("The app will connect to OpenAI API server to check if your API Key is working properly.") + Text(Localization.TheAppWillConnectOpenAIServer.localized) .font(.footnote) .fontWeight(.bold) .frame(maxWidth: .infinity, alignment: .center) diff --git a/OSXChatGPT/OSXChatGPT/WindowView/SessionsView.swift b/OSXChatGPT/OSXChatGPT/WindowView/SessionsView.swift index 45c2d7a..078310d 100644 --- a/OSXChatGPT/OSXChatGPT/WindowView/SessionsView.swift +++ b/OSXChatGPT/OSXChatGPT/WindowView/SessionsView.swift @@ -33,7 +33,7 @@ struct SessionsView: View { HStack(spacing: 0) { Text(" ") Image(systemName: "plus.message.fill") - Text("New Chat ") + Text(Localization.newChat.localized) } .padding(10) .foregroundColor(.white) @@ -141,12 +141,23 @@ struct ChatRowView: View { .padding(.leading, 5) VStack(alignment: .leading) { if let prompt = chat.prompt?.title { - Text("[修饰]\(prompt)") + Text(Localization.prompt(prompt).localized) .font(.headline) .foregroundColor(NSColor(r: 224, g: 87, b: 114).toColor()) }else { - Text(chat.prompt?.title ?? chat.remark ?? chat.lastMessage?.text ?? "New Chat") - .font(.headline) + if chat.prompt?.title != nil { + Text(chat.prompt?.title ?? "") + .font(.headline) + }else if chat.remark != nil { + Text(chat.remark ?? "") + .font(.headline) + }else if chat.lastMessage?.text != nil { + Text(chat.lastMessage?.text ?? "") + .font(.headline) + }else { + Text(Localization.newChat.localized) + .font(.headline) + } } Spacer() @@ -201,10 +212,10 @@ struct ChatRowContentNSView: NSViewRepresentable { @objc func handleRightClick(_ sender: NSClickGestureRecognizer) { if sender.state == .ended { print("右键鼠标") - let menu = NSMenu(title: "123") + let menu = NSMenu(title: "") menu.delegate = self - let editMenuItem = NSMenuItem(title: "编辑备注", action: #selector(edit), keyEquivalent: "") - let deleteMenuItem = NSMenuItem(title: "删除会话", action: #selector(delete), keyEquivalent: "") + let editMenuItem = NSMenuItem(title: Localization.editRemark.localized, action: #selector(edit), keyEquivalent: "") + let deleteMenuItem = NSMenuItem(title: Localization.deleteSession.localized, action: #selector(delete), keyEquivalent: "") editMenuItem.target = self deleteMenuItem.target = self menu.addItem(editMenuItem) diff --git a/OSXChatGPT/OSXChatGPT/WindowView/UserInitializeView.swift b/OSXChatGPT/OSXChatGPT/WindowView/UserInitializeView.swift index 65e52a9..ae80e5d 100644 --- a/OSXChatGPT/OSXChatGPT/WindowView/UserInitializeView.swift +++ b/OSXChatGPT/OSXChatGPT/WindowView/UserInitializeView.swift @@ -43,19 +43,19 @@ struct UserInitializeView: View { VStack(alignment: .leading, spacing: 10){ HStack { - Text("✅ Faster response ✅ Local Chat History") + Text(Localization.fasterResponse.localized) .fixedSize(horizontal: true, vertical: false) } HStack { - Text("✅ Prompt Library ✅ Run locally on desktop") + Text(Localization.PromptLibrary.localized) .fixedSize(horizontal: true, vertical: false) } HStack { - Text("✅ No login required ✅ Use your own API key") + Text(Localization.NoLoginRequired.localized) .fixedSize(horizontal: true, vertical: false) } HStack { - Text("✅ No monthly fee and more soon...") + Text(Localization.NoMonthlyFee.localized) .fixedSize(horizontal: true, vertical: false) } } @@ -69,7 +69,7 @@ struct UserInitializeView: View { }) { HStack(spacing: 0, content:{ Image("github-fill 1") - Text("A Better macOS application for ChatGPT") + Text(Localization.BetterApplication.localized) .foregroundColor(.blue) .frame(maxWidth: 250, alignment: .leading) .padding(.horizontal, 5) @@ -83,7 +83,7 @@ struct UserInitializeView: View { }) { HStack(spacing: 0, content:{ Image(systemName: "play.tv.fill") - Text("湖畔机械厂电影院") + Text(Localization.adMovie.localized) .foregroundColor(.blue) .frame(maxWidth: 250, alignment: .leading) .padding(.horizontal, 5) @@ -97,7 +97,7 @@ struct UserInitializeView: View { }) { HStack(spacing: 0, content:{ Image(systemName: "desktopcomputer.and.arrow.down") - Text("湖畔机械厂员工搬运Mac软件资源网") + Text(Localization.adWebsite.localized) .foregroundColor(.blue) .frame(maxWidth: 250, alignment: .leading) .padding(.horizontal, 5) @@ -112,10 +112,10 @@ struct UserInitializeView: View { HStack(spacing: 8) { if apiKey.count > 0 { Image(systemName: "person.fill.checkmark") - Text("Update API Key") + Text(Localization.UpdateAPIKey.localized) } else { Image(systemName: "key.radiowaves.forward.fill") - Text("Enter API Key") + Text(Localization.EnterAPIKey.localized) } } .foregroundColor(.white) diff --git a/OSXChatGPT/OSXChatGPT/en.lproj/Localizable.strings b/OSXChatGPT/OSXChatGPT/en.lproj/Localizable.strings new file mode 100644 index 0000000..1d70b0f --- /dev/null +++ b/OSXChatGPT/OSXChatGPT/en.lproj/Localizable.strings @@ -0,0 +1,65 @@ +/* + Localizable.strings + OSXChatGPT + + Created by CoderChan on 2023/4/20. + +*/ + + +"newChat" = "New Chat "; +"Prompt" = "[Prompt]%@"; +"editRemark" = "editRemark"; +"deleteSession" = "deleteSession"; +"EditConversationRemark" = "Edit Conversation Remark:"; +"EnterRemark" = "Enter remark"; + +"FasterResponse" = "✅ Faster response ✅ Local Chat History"; +"PromptLibrary" = "✅ Prompt Library ✅ Run locally on desktop"; +"NoLoginRequired" = "✅ No login required ✅ Use your own API key"; +"NoMonthlyFee" = "✅ No monthly fee and more soon..."; +"BetterApplication" = "A Better macOS application for ChatGPT"; +"adMovie" = "湖畔机械厂电影院"; +"adWebsite" = "湖畔机械厂员工搬运Mac软件资源网"; +"UpdateAPIKey" = "Update API Key"; +"EnterAPIKey" = "Enter API Key"; +"EnterYourAPIKey" = "Enter Your OpenAI API Key:"; +"YouNeedApiKey" = "You need a working OpenAI Api Key in order to use OSXChatGPT"; +"GetYourAPIKey" = "🌏 Get your API key from Open AI dashboard"; +"Cancel" = "Cancel"; +"Save" = "Save"; +"TheAppWillConnectOpenAIServer" = "The app will connect to OpenAI API server to check if your API Key is working properly."; + +"deleteMessage" = "delete message"; +"copyMessage" = "copy message"; +"ParameterAdjustment" = "Parameter"; +"TemperatureT" = "Temperature(%@)"; +"ModelT" = "Model(%@)"; +"ContextT" = "Context(%@dialog)"; +"Answer" = "Answer"; +"Prompts" = "Prompts"; +"ClearMessage" = "Clear message"; +"StopAnswer" = "Stop answer"; +"Empty" = "Empty"; +"CurrentTemperature" = "Current temperature:"; + +"RemoveShortcuts" = "Remove shortcuts"; +"AddShortcuts" = "Add shortcuts"; +"DeleteData" = "Delete data"; +"PleaseClickUpperRightAddCustomPrompt" = "Please click in the upper right corner to add a new custom Prompt"; +"SelectPrompt" = "Select prompt"; +"Confirm" = "Confirm"; +"Library" = "Library"; +"DefaultNoPrompt" = "【Default no prompt】"; +"CurrentSelectPrompt" = "Current select prompt"; +"NoPromptToLibraryAdd" = "(No prompt, please add to library)"; +"SelectOnlyOnePromptPerSession" = "You can select only one prompt per session, or you can add custom prompt"; +"CustomAdd" = "Custom add"; +"Title" = "Title"; +"Required" = "*Required"; +"Author" = "Author"; +"ShareYourPromptToLibrary" = "Share your prompt with library"; +"ShareOrNot" = "Share or not"; + +"AnswerStream" = "Stream"; +"AnswerOneTime" = "OneTime"; diff --git a/OSXChatGPT/OSXChatGPT/zh-Hans.lproj/Localizable.strings b/OSXChatGPT/OSXChatGPT/zh-Hans.lproj/Localizable.strings new file mode 100644 index 0000000..55ab356 --- /dev/null +++ b/OSXChatGPT/OSXChatGPT/zh-Hans.lproj/Localizable.strings @@ -0,0 +1,64 @@ +/* + Localizable.strings + OSXChatGPT + + Created by CoderChan on 2023/4/20. + +*/ + +"newChat" = "新会话 "; +"Prompt" = "[修饰]%@"; +"editRemark" = "编辑备注"; +"deleteSession" = "删除会话"; +"EditConversationRemark" = "编辑会话备注:"; +"EnterRemark" = "输入备注"; + +"FasterResponse" = "✅ 更快的响应 ✅ 本地聊天记录"; +"PromptLibrary" = "✅ 修饰词库 ✅ 在桌面上本地运行"; +"NoLoginRequired" = "✅ 无需登陆 ✅ 使用您的API密钥"; +"NoMonthlyFee" = "✅ 没有任何费用 还有更多..."; +"BetterApplication" = "一个优秀的macOS应用程序的ChatGPT"; +"adMovie" = "湖畔机械厂电影院"; +"adWebsite" = "湖畔机械厂员工搬运Mac软件资源网"; +"UpdateAPIKey" = "更新 API Key"; +"EnterAPIKey" = "填入 API Key"; +"EnterYourAPIKey" = "填入你的 API Key:"; +"YouNeedApiKey" = "使用OSXChatGPT之前你需要OpenAI的Api Key"; +"GetYourAPIKey" = "🌏 去OpenAI官网获取Api Key"; +"Cancel" = "取消"; +"Save" = "保存"; +"TheAppWillConnectOpenAIServer" = "该应用程序将连接到OpenAI API服务器,需要检查您的API密钥是否正常工作。"; + +"deleteMessage" = "删除消息"; +"copyMessage" = "复制消息"; +"ParameterAdjustment" = "参数调节"; +"TemperatureT" = "温度调节(%@)"; +"ModelT" = "模型(%@)"; +"ContextT" = "上下文(%@组对话)"; +"Answer" = "应答"; +"Prompts" = "修饰语"; +"ClearMessage" = "清空消息"; +"StopAnswer" = "停止生成"; +"Empty" = "空"; +"CurrentTemperature" = "当前温度:"; + +"RemoveShortcuts" = "删除快捷方式"; +"AddShortcuts" = "移除快捷方式"; +"DeleteData" = "删除数据"; +"PleaseClickUpperRightAddCustomPrompt" = "请点击右上角自定义添加新的修饰语"; +"SelectPrompt" = "选择修饰语"; +"Confirm" = "确定"; +"Library" = "词库"; +"DefaultNoPrompt" = "【默认无修饰语】"; +"CurrentSelectPrompt" = "当前选中的修饰语"; +"NoPromptToLibraryAdd" = "(没有修饰语,请到词库添加)"; +"SelectOnlyOnePromptPerSession" = "每个会话只能选择一个修饰语, 也可以自定义添加修饰语"; +"CustomAdd" = "自定义添加"; +"Title" = "标题"; +"Required" = "*必填"; +"Author" = "作者"; +"ShareYourPromptToLibrary" = "分享您的修饰语到词库"; +"ShareOrNot" = "是否分享"; + +"AnswerStream" = "流式"; +"AnswerOneTime" = "单式";