diff --git a/Source/Modules/UIModules/PrefUITabs.swift b/Source/Modules/UIModules/PrefUITabs.swift
new file mode 100644
index 00000000..522d7e4d
--- /dev/null
+++ b/Source/Modules/UIModules/PrefUITabs.swift
@@ -0,0 +1,86 @@
+// (c) 2021 and onwards The vChewing Project (MIT-NTL License).
+// ====================
+// This code is released under the MIT license (SPDX-License-Identifier: MIT)
+// ... with NTL restriction stating that:
+// No trademark license is granted to use the trade names, trademarks, service
+// marks, or product names of Contributor, except as required to fulfill notice
+// requirements defined in MIT License.
+
+import Cocoa
+import Shared
+
+enum PrefUITabs: String, CaseIterable {
+ case tabGeneral = "General"
+ case tabCandidates = "Candidates"
+ case tabBehavior = "Behavior"
+ case tabOutput = "Output"
+ case tabDictionary = "Dictionary"
+ case tabPhrases = "Phrases"
+ case tabCassette = "Cassette"
+ case tabKeyboard = "Keyboard"
+ case tabDevZone = "DevZone"
+ case tabExperience = "Experience"
+}
+
+extension PrefUITabs {
+ private static let i18nTable: [String: (Hans: String, Hant: String, Ja: String)] = [
+ "General": (Hans: "一般设定", Hant: "一般設定", Ja: "一般設定"),
+ "Candidates": (Hans: "选字设定", Hant: "選字設定", Ja: "候補設定"),
+ "Behavior": (Hans: "行为设定", Hant: "行為設定", Ja: "作動設定"),
+ "Output": (Hans: "输出设定", Hant: "輸出設定", Ja: "出力設定"),
+ "Dictionary": (Hans: "辞典设定", Hant: "辭典設定", Ja: "辞書設定"),
+ "Phrases": (Hans: "语汇编辑", Hant: "語彙編輯", Ja: "辞書編集"),
+ "Cassette": (Hans: "磁带设定", Hant: "磁帶設定", Ja: "カセ設定"),
+ "Keyboard": (Hans: "键盘设定", Hant: "鍵盤設定", Ja: "配列設定"),
+ "DevZone": (Hans: "开发道场", Hant: "開發道場", Ja: "開発道場"),
+ "Experience": (Hans: "体验设定", Hant: "體驗設定", Ja: "体験設定"),
+ ]
+
+ var toolbarIdentifier: NSToolbarItem.Identifier { .init(rawValue: rawValue) }
+
+ var i18nTitle: String {
+ switch PrefMgr.shared.appleLanguages[0] {
+ case "ja": return Self.i18nTable[rawValue]?.Ja ?? rawValue
+ default:
+ if PrefMgr.shared.appleLanguages[0].contains("zh-Hans") {
+ return Self.i18nTable[rawValue]?.Hans ?? rawValue
+ } else if PrefMgr.shared.appleLanguages[0].contains("zh-Hant") {
+ return Self.i18nTable[rawValue]?.Hant ?? rawValue
+ }
+ return rawValue
+ }
+ }
+
+ var icon: NSImage {
+ if #available(macOS 11.0, *) {
+ let name: String = {
+ switch self {
+ case .tabGeneral:
+ return "wrench.and.screwdriver.fill"
+ case .tabCandidates:
+ return "filemenu.and.selection"
+ case .tabBehavior:
+ return "switch.2"
+ case .tabOutput:
+ return "text.append"
+ case .tabDictionary:
+ return "text.book.closed.fill"
+ case .tabPhrases:
+ return "tablecells.badge.ellipsis"
+ case .tabCassette:
+ return "externaldrive.fill.badge.plus"
+ case .tabKeyboard:
+ return "keyboard.macwindow"
+ case .tabDevZone:
+ return "pc"
+ case .tabExperience:
+ return "person.fill.questionmark"
+ }
+ }()
+ let note = "\(self.rawValue) Preferences"
+ return NSImage(systemSymbolName: name, accessibilityDescription: note) ?? NSImage()
+ }
+ let legacyName = "PrefToolbar-\(rawValue)"
+ return NSImage(named: legacyName) ?? NSImage()
+ }
+}
diff --git a/Source/WindowNIBs/Base.lproj/frmPrefWindow.xib b/Source/WindowNIBs/Base.lproj/frmPrefWindow.xib
index c4f905e4..395fcc1a 100644
--- a/Source/WindowNIBs/Base.lproj/frmPrefWindow.xib
+++ b/Source/WindowNIBs/Base.lproj/frmPrefWindow.xib
@@ -1771,7 +1771,7 @@
-
+
diff --git a/vChewing.xcodeproj/project.pbxproj b/vChewing.xcodeproj/project.pbxproj
index 39a5ebb5..1539a90a 100644
--- a/vChewing.xcodeproj/project.pbxproj
+++ b/vChewing.xcodeproj/project.pbxproj
@@ -59,6 +59,7 @@
5BA9FD1327FEDB6B002DE248 /* VwrPrefPaneDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA9FD0E27FEDB6B002DE248 /* VwrPrefPaneDictionary.swift */; };
5BAD0CD527D701F6003D127F /* vChewingKeyLayout.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 5B30F11227BA568800484E24 /* vChewingKeyLayout.bundle */; };
5BAEFAD028012565001F42C9 /* LMMgr.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BAEFACF28012565001F42C9 /* LMMgr.swift */; };
+ 5BB1D7F42999027200EA8D2C /* PrefUITabs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BB1D7F32999027200EA8D2C /* PrefUITabs.swift */; };
5BB802DA27FABA8300CF1C19 /* SessionCtl_Menu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BB802D927FABA8300CF1C19 /* SessionCtl_Menu.swift */; };
5BBBB75F27AED54C0023B93A /* Beep.m4a in Resources */ = {isa = PBXBuildFile; fileRef = 5BBBB75D27AED54C0023B93A /* Beep.m4a */; };
5BBBB76027AED54C0023B93A /* Fart.m4a in Resources */ = {isa = PBXBuildFile; fileRef = 5BBBB75E27AED54C0023B93A /* Fart.m4a */; };
@@ -251,6 +252,7 @@
5BA9FD0D27FEDB6B002DE248 /* VwrPrefPaneExperience.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = VwrPrefPaneExperience.swift; sourceTree = ""; tabWidth = 2; usesTabs = 0; };
5BA9FD0E27FEDB6B002DE248 /* VwrPrefPaneDictionary.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = VwrPrefPaneDictionary.swift; sourceTree = ""; tabWidth = 2; usesTabs = 0; };
5BAEFACF28012565001F42C9 /* LMMgr.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = LMMgr.swift; sourceTree = ""; tabWidth = 2; usesTabs = 0; };
+ 5BB1D7F32999027200EA8D2C /* PrefUITabs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrefUITabs.swift; sourceTree = ""; };
5BB802D927FABA8300CF1C19 /* SessionCtl_Menu.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = SessionCtl_Menu.swift; sourceTree = ""; tabWidth = 2; usesTabs = 0; };
5BBBB75D27AED54C0023B93A /* Beep.m4a */ = {isa = PBXFileReference; lastKnownFileType = file; path = Beep.m4a; sourceTree = ""; };
5BBBB75E27AED54C0023B93A /* Fart.m4a */ = {isa = PBXFileReference; lastKnownFileType = file; path = Fart.m4a; sourceTree = ""; };
@@ -465,6 +467,7 @@
children = (
5B62A33E27AE7CD900A19448 /* CandidateUI */,
5BA9FD0927FED9F3002DE248 /* PrefUI */,
+ 5BB1D7F32999027200EA8D2C /* PrefUITabs.swift */,
);
path = UIModules;
sourceTree = "";
@@ -1102,6 +1105,7 @@
5B30BF282944867800BD87A9 /* CtlRevLookupWindow.swift in Sources */,
5BD0113D2818543900609769 /* InputHandler_Core.swift in Sources */,
5BF56F9A28C39D1800DD6839 /* IMEStateData.swift in Sources */,
+ 5BB1D7F42999027200EA8D2C /* PrefUITabs.swift in Sources */,
5B21176C287539BB000443A9 /* SessionCtl_HandleStates.swift in Sources */,
5BE1F8A928F86AB5006C7FF5 /* InputHandler_HandleEvent.swift in Sources */,
5B69938C293B811F0057CB8E /* VwrPrefPanePhrases.swift in Sources */,