Skip to content

Commit 17b7a64

Browse files
author
evan.zhao
committed
Localize app interface
1 parent c61787f commit 17b7a64

30 files changed

Lines changed: 1793 additions & 372 deletions

Package.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import PackageDescription
44

55
let package = Package(
66
name: "ClipDock",
7+
defaultLocalization: "zh-Hans",
78
platforms: [
89
.macOS(.v13)
910
],
@@ -26,7 +27,10 @@ let package = Package(
2627
dependencies: [
2728
.product(name: "ClipboardCoreBridge", package: "ClipboardCoreBridge")
2829
],
29-
path: "Sources/ClipboardPanelApp"
30+
path: "Sources/ClipboardPanelApp",
31+
resources: [
32+
.process("Resources")
33+
]
3034
),
3135
.executableTarget(
3236
name: "ClipDock",

Sources/ClipDock/AppRuntime.swift

Lines changed: 55 additions & 52 deletions
Large diffs are not rendered by default.

Sources/ClipDock/ApplicationRuntime.swift

Lines changed: 56 additions & 47 deletions
Large diffs are not rendered by default.

Sources/ClipDock/CopyCompletionHUDController.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,12 +134,15 @@ final class CopyCompletionHUDController {
134134
shadowHost.addSubview(card)
135135

136136
let icon = NSImageView()
137-
icon.image = NSImage(systemSymbolName: "checkmark", accessibilityDescription: "已复制")
137+
icon.image = NSImage(
138+
systemSymbolName: "checkmark",
139+
accessibilityDescription: AppLocalization.text("copy.completed", defaultValue: "已复制")
140+
)
138141
icon.symbolConfiguration = NSImage.SymbolConfiguration(pointSize: 72, weight: .medium)
139142
icon.contentTintColor = CopyCompletionHUDPalette.foreground
140143
icon.translatesAutoresizingMaskIntoConstraints = false
141144

142-
let label = NSTextField(labelWithString: "已复制")
145+
let label = NSTextField(labelWithString: AppLocalization.text("copy.completed", defaultValue: "已复制"))
143146
label.font = .systemFont(ofSize: 22, weight: .regular)
144147
label.textColor = CopyCompletionHUDPalette.foreground
145148
label.alignment = .center
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import Foundation
2+
3+
enum AppLocalization {
4+
static func text(_ key: String, defaultValue: String) -> String {
5+
if isRunningPackageTests {
6+
return defaultValue
7+
}
8+
return NSLocalizedString(key, bundle: .module, value: defaultValue, comment: "")
9+
}
10+
11+
static func format(_ key: String, defaultValue: String, _ arguments: CVarArg...) -> String {
12+
String(
13+
format: text(key, defaultValue: defaultValue),
14+
locale: Locale.current,
15+
arguments: arguments
16+
)
17+
}
18+
19+
static func itemTypeTitle(_ itemType: String) -> String {
20+
switch itemType {
21+
case "link":
22+
return text("item.type.link", defaultValue: "链接")
23+
case "image":
24+
return text("item.type.image", defaultValue: "图片")
25+
case "file":
26+
return text("item.type.file", defaultValue: "文件")
27+
case "color":
28+
return text("item.type.color", defaultValue: "颜色")
29+
case "rich_text":
30+
return text("item.type.richText", defaultValue: "富文本")
31+
default:
32+
return text("item.type.text", defaultValue: "文本")
33+
}
34+
}
35+
36+
private static var isRunningPackageTests: Bool {
37+
let processInfo = ProcessInfo.processInfo
38+
return processInfo.processName.contains("PackageTests")
39+
|| Bundle.main.bundlePath.contains("PackageTests")
40+
|| CommandLine.arguments.contains { $0.contains("PackageTests") || $0.contains(".xctest") }
41+
|| processInfo.environment["XCTestConfigurationFilePath"] != nil
42+
}
43+
}

Sources/ClipDock/PanelCardSupport.swift

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,9 @@ final class PanelCardAssetResolver {
137137
paths: paths,
138138
image: Self.cachedPreviewImage(paths: paths),
139139
tooltip: [previewPath, payloadPath].compactMap { $0 }.joined(separator: "\n"),
140-
fallbackText: paths.isEmpty ? "预览不可用" : "载入预览"
140+
fallbackText: paths.isEmpty
141+
? AppLocalization.text("preview.unavailable", defaultValue: "预览不可用")
142+
: AppLocalization.text("preview.loading", defaultValue: "载入预览")
141143
)
142144
}
143145

@@ -238,7 +240,7 @@ final class PanelCardAssetResolver {
238240
return icon
239241
}
240242

241-
return NSImage(systemSymbolName: "folder", accessibilityDescription: "文件")
243+
return NSImage(systemSymbolName: "folder", accessibilityDescription: AppLocalization.itemTypeTitle("file"))
242244
}
243245

244246
func filePreviewURLs(for request: PanelCardAssetRequest) -> [URL] {
@@ -346,11 +348,11 @@ final class PanelCardAssetResolver {
346348
sourceIconColor: NSColor?,
347349
isSelected: Bool
348350
) -> NSColor {
349-
if typeText.contains("错误") {
351+
if typeText.contains(AppLocalization.text("status.error", defaultValue: "错误")) {
350352
return NSColor.systemRed.withAlphaComponent(isSelected ? 0.96 : 0.88)
351353
}
352354

353-
if typeText.contains("空态") {
355+
if typeText.contains(AppLocalization.text("status.empty", defaultValue: "空态")) {
354356
return NSColor.systemGray.withAlphaComponent(isSelected ? 0.90 : 0.82)
355357
}
356358

@@ -363,15 +365,15 @@ final class PanelCardAssetResolver {
363365
return sourceHeaderColor(for: sourceColorKey, isSelected: isSelected)
364366
}
365367

366-
if typeText.contains("链接") {
368+
if typeText.contains(AppLocalization.itemTypeTitle("link")) {
367369
return NSColor.systemPurple.withAlphaComponent(isSelected ? 1 : 0.92)
368370
}
369371

370-
if typeText.contains("图片") {
372+
if typeText.contains(AppLocalization.itemTypeTitle("image")) {
371373
return NSColor.systemBlue.withAlphaComponent(isSelected ? 1 : 0.86)
372374
}
373375

374-
if typeText.contains("文件") {
376+
if typeText.contains(AppLocalization.itemTypeTitle("file")) {
375377
return NSColor.systemBlue.withAlphaComponent(isSelected ? 0.94 : 0.78)
376378
}
377379

Sources/ClipDock/PanelItemCardRenderer.swift

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -735,7 +735,7 @@ final class PanelItemCardRenderer {
735735
)
736736
case .file:
737737
return makeFilePreview(
738-
accessibilityLabel: assetRequest.sourceAppName ?? "文件",
738+
accessibilityLabel: assetRequest.sourceAppName ?? AppLocalization.itemTypeTitle("file"),
739739
assetRequest: assetRequest
740740
)
741741
case .color(let colorValue):
@@ -819,7 +819,9 @@ final class PanelItemCardRenderer {
819819
guard imageView?.identifier == loadIdentifier else { return }
820820
imageView?.previewImageLoadToken = nil
821821
imageView?.image = image
822-
fallbackLabel?.stringValue = image == nil ? "预览不可用" : ""
822+
fallbackLabel?.stringValue = image == nil
823+
? AppLocalization.text("preview.unavailable", defaultValue: "预览不可用")
824+
: ""
823825
fallbackLabel?.isHidden = image != nil
824826
}
825827
}
@@ -1040,8 +1042,8 @@ final class PanelItemCardRenderer {
10401042
}
10411043

10421044
private func defaultLinkBrowserIcon() -> NSImage? {
1043-
let image = NSImage(systemSymbolName: "safari", accessibilityDescription: "Safari 浏览器")
1044-
?? NSImage(systemSymbolName: "globe", accessibilityDescription: "浏览器")
1045+
let image = NSImage(systemSymbolName: "safari", accessibilityDescription: AppLocalization.text("browser.safari", defaultValue: "Safari 浏览器"))
1046+
?? NSImage(systemSymbolName: "globe", accessibilityDescription: AppLocalization.text("browser.generic", defaultValue: "浏览器"))
10451047
image?.isTemplate = true
10461048
return image
10471049
}

Sources/ClipDock/PanelPreviewUI.swift

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,7 @@ private final class ClipboardPreviewViewController: NSViewController {
477477
closeButton.onPress = { [weak self] in
478478
self?.onClose?()
479479
}
480-
closeButton.toolTip = "关闭预览"
480+
closeButton.toolTip = AppLocalization.text("preview.close", defaultValue: "关闭预览")
481481
closeButton.translatesAutoresizingMaskIntoConstraints = false
482482

483483
let titleLabel = NSTextField(labelWithString: displayTypeTitle())
@@ -924,17 +924,17 @@ private final class ClipboardPreviewViewController: NSViewController {
924924
private func displayTypeTitle() -> String {
925925
switch content.itemType {
926926
case "link":
927-
return "链接"
927+
return AppLocalization.itemTypeTitle("link")
928928
case "image":
929-
return "图片"
929+
return AppLocalization.itemTypeTitle("image")
930930
case "file":
931-
return "文件"
931+
return AppLocalization.itemTypeTitle("file")
932932
case "color":
933-
return "颜色"
933+
return AppLocalization.itemTypeTitle("color")
934934
case "rich_text":
935-
return "富文本"
935+
return AppLocalization.itemTypeTitle("rich_text")
936936
default:
937-
return "文本"
937+
return AppLocalization.itemTypeTitle("text")
938938
}
939939
}
940940

@@ -947,7 +947,10 @@ private final class ClipboardPreviewViewController: NSViewController {
947947

948948
if content.itemType == "file", !content.fileURLs.isEmpty {
949949
if content.fileURLs.count > 1 {
950-
return ["\(content.fileURLs.count) 个文件", content.fileURLs[0].path]
950+
return [
951+
AppLocalization.format("preview.fileCount", defaultValue: "%lld 个文件", Int64(content.fileURLs.count)),
952+
content.fileURLs[0].path
953+
]
951954
}
952955
return [content.fileURLs[0].path]
953956
}
@@ -964,8 +967,8 @@ private final class ClipboardPreviewViewController: NSViewController {
964967
let characterCount = text.count
965968
let lineCount = text.isEmpty ? 0 : text.split(separator: "\n", omittingEmptySubsequences: false).count
966969
return [
967-
"\(Self.decimalString(characterCount)) 个字符",
968-
"\(Self.decimalString(lineCount))"
970+
AppLocalization.format("preview.characterCount", defaultValue: "%@ 个字符", Self.decimalString(characterCount)),
971+
AppLocalization.format("preview.lineCount", defaultValue: "%@ 行", Self.decimalString(lineCount))
969972
]
970973
}
971974

@@ -1538,7 +1541,7 @@ private final class PreviewImageDocumentView: NSView {
15381541
.font: NSFont.systemFont(ofSize: 14, weight: .medium),
15391542
.foregroundColor: NSColor.secondaryLabelColor
15401543
]
1541-
let text = NSString(string: "预览不可用")
1544+
let text = NSString(string: AppLocalization.text("preview.unavailable", defaultValue: "预览不可用"))
15421545
let size = text.size(withAttributes: attributes)
15431546
text.draw(
15441547
at: NSPoint(x: bounds.midX - size.width / 2, y: bounds.midY - size.height / 2),

Sources/ClipDock/PanelUIPrimitives.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,22 @@ enum PanelLevelMode: String, CaseIterable {
1010
var title: String {
1111
switch self {
1212
case .floating:
13-
return "普通悬浮"
13+
return AppLocalization.text("panel.level.floating", defaultValue: "普通悬浮")
1414
case .statusBar:
15-
return "状态栏层级"
15+
return AppLocalization.text("panel.level.statusBar", defaultValue: "状态栏层级")
1616
case .aboveDock:
17-
return "高于 Dock"
17+
return AppLocalization.text("panel.level.aboveDock", defaultValue: "高于 Dock")
1818
}
1919
}
2020

2121
var detail: String {
2222
switch self {
2323
case .floating:
24-
return "NSWindow.Level.floating,适合大多数工具面板"
24+
return AppLocalization.text("panel.level.floating.detail", defaultValue: "NSWindow.Level.floating,适合大多数工具面板")
2525
case .statusBar:
26-
return "NSWindow.Level.statusBar,层级更高"
26+
return AppLocalization.text("panel.level.statusBar.detail", defaultValue: "NSWindow.Level.statusBar,层级更高")
2727
case .aboveDock:
28-
return "CGWindowLevel(.dockWindow) + 1,可压到 Dock 层级之上"
28+
return AppLocalization.text("panel.level.aboveDock.detail", defaultValue: "CGWindowLevel(.dockWindow) + 1,可压到 Dock 层级之上")
2929
}
3030
}
3131
}

0 commit comments

Comments
 (0)