Skip to content

Commit 405ee73

Browse files
authored
[#406] 위젯에 로컬라이제이션을 구현한다 (#407)
* chore: l10n 진행 * chore: Xcode 지역화 설정 갱신 * ui: 'Heatmap' 제거 * ui: 요일 라벨 제거
1 parent 1998151 commit 405ee73

13 files changed

Lines changed: 144 additions & 81 deletions

DevLog.xcodeproj/project.pbxproj

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@
275275
attributes = {
276276
BuildIndependentTargetsInParallel = 1;
277277
LastSwiftUpdateCheck = 2640;
278-
LastUpgradeCheck = 2600;
278+
LastUpgradeCheck = 2640;
279279
TargetAttributes = {
280280
DF3416442E45F67C00F9312B = {
281281
CreatedOnToolsVersion = 16.3;
@@ -295,6 +295,7 @@
295295
knownRegions = (
296296
ko,
297297
en,
298+
Base,
298299
);
299300
mainGroup = DFD48AF72DC4D6E2005905C5;
300301
minimizedProjectReferenceProxies = 1;
@@ -603,6 +604,7 @@
603604
buildSettings = {
604605
ALWAYS_SEARCH_USER_PATHS = NO;
605606
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
607+
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
606608
CLANG_ANALYZER_NONNULL = YES;
607609
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
608610
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
@@ -671,6 +673,7 @@
671673
buildSettings = {
672674
ALWAYS_SEARCH_USER_PATHS = NO;
673675
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
676+
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
674677
CLANG_ANALYZER_NONNULL = YES;
675678
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
676679
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";

DevLog.xcodeproj/xcshareddata/xcschemes/DevLog.xcscheme

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<Scheme
3-
LastUpgradeVersion = "2600"
3+
LastUpgradeVersion = "2640"
44
version = "1.7">
55
<BuildAction
66
parallelizeBuildables = "YES"

DevLog.xcodeproj/xcshareddata/xcschemes/DevLogWidgetExtension.xcscheme

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,16 +58,26 @@
5858
allowLocationSimulation = "YES"
5959
launchAutomaticallySubstyle = "2"
6060
queueDebuggingEnableBacktraceRecording = "Yes">
61-
<BuildableProductRunnable
62-
runnableDebuggingMode = "0">
61+
<RemoteRunnable
62+
runnableDebuggingMode = "2"
63+
BundleIdentifier = "com.apple.springboard">
64+
<BuildableReference
65+
BuildableIdentifier = "primary"
66+
BlueprintIdentifier = "DFD3A96F2F8E89DD001DA7CD"
67+
BuildableName = "DevLogWidgetExtension.appex"
68+
BlueprintName = "DevLogWidgetExtension"
69+
ReferencedContainer = "container:DevLog.xcodeproj">
70+
</BuildableReference>
71+
</RemoteRunnable>
72+
<MacroExpansion>
6373
<BuildableReference
6474
BuildableIdentifier = "primary"
6575
BlueprintIdentifier = "DFD48AFF2DC4D6E2005905C5"
6676
BuildableName = "DevLog.app"
6777
BlueprintName = "DevLog"
6878
ReferencedContainer = "container:DevLog.xcodeproj">
6979
</BuildableReference>
70-
</BuildableProductRunnable>
80+
</MacroExpansion>
7181
<EnvironmentVariables>
7282
<EnvironmentVariable
7383
key = "_XCWidgetKind"

DevLog.xcodeproj/xcshareddata/xcschemes/DevLog_Unit.xcscheme

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<Scheme
3-
LastUpgradeVersion = "2600"
3+
LastUpgradeVersion = "2640"
44
version = "1.7">
55
<BuildAction
66
parallelizeBuildables = "YES"

DevLogWidget/Heatmap/HeatmapWidget.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ struct HeatmapWidget: Widget {
2323
.widgetURL(WidgetDeepLink.heatmapURL)
2424
}
2525
.configurationDisplayName("Heatmap")
26-
.description("활동 히트맵을 표시합니다.")
26+
.description("widget_heatmap_description")
2727
.supportedFamilies([.systemSmall, .systemMedium])
2828
}
2929
}

DevLogWidget/Heatmap/HeatmapWidgetConfigurationIntent.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,5 @@ import WidgetKit
1010

1111
struct HeatmapWidgetConfigurationIntent: WidgetConfigurationIntent {
1212
static var title: LocalizedStringResource = "Heatmap"
13-
static var description = IntentDescription("활동 히트맵을 표시합니다.")
13+
static var description = IntentDescription("widget_heatmap_description")
1414
}

DevLogWidget/Heatmap/HeatmapWidgetEntryView.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ struct HeatmapWidgetEntryView: View {
2828
switch widgetFamily {
2929
case .systemSmall:
3030
VStack(alignment: .leading, spacing: 4) {
31-
header(title: "이번 달 히트맵")
31+
header(title: "widget_heatmap_current_month_title")
3232
WidgetHeatmapGrid(
3333
months: currentMonths(from: snapshot),
3434
selectedActivityKindRawValues: snapshot.selectedActivityKindRawValues,
@@ -38,7 +38,7 @@ struct HeatmapWidgetEntryView: View {
3838
}
3939
case .systemMedium:
4040
VStack(alignment: .leading, spacing: 8) {
41-
header(title: "이번 분기 히트맵")
41+
header(title: "widget_heatmap_current_quarter_title")
4242
WidgetHeatmapGrid(
4343
months: snapshot.months,
4444
selectedActivityKindRawValues: snapshot.selectedActivityKindRawValues,
@@ -58,15 +58,15 @@ struct HeatmapWidgetEntryView: View {
5858
switch widgetFamily {
5959
case .systemSmall:
6060
VStack(alignment: .leading, spacing: 8) {
61-
header(title: "이번 달 히트맵")
61+
header(title: "widget_heatmap_current_month_title")
6262
WidgetHeatmapPlaceholderGrid(
6363
months: shape.currentMonths,
6464
showsMonthTitles: false
6565
)
6666
}
6767
case .systemMedium:
6868
VStack(alignment: .leading, spacing: 8) {
69-
header(title: "이번 분기 히트맵")
69+
header(title: "widget_heatmap_current_quarter_title")
7070
WidgetHeatmapPlaceholderGrid(
7171
months: shape.quarterMonths,
7272
showsMonthTitles: true
@@ -77,7 +77,7 @@ struct HeatmapWidgetEntryView: View {
7777
}
7878
}
7979

80-
private func header(title: String) -> some View {
80+
private func header(title: LocalizedStringKey) -> some View {
8181
HStack(alignment: .firstTextBaseline, spacing: 6) {
8282
Text(title)
8383
.font(.headline)

DevLogWidget/Heatmap/WidgetHeatmapGrid.swift

Lines changed: 9 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -22,19 +22,15 @@ struct WidgetHeatmapGrid: View {
2222
showsMonthTitles: showsMonthTitles
2323
)
2424

25-
HStack(alignment: .top, spacing: layout.weekdayLabelSpacing) {
26-
WidgetHeatmapWeekdayLabels(layout: layout)
27-
28-
HStack(alignment: .top, spacing: layout.monthSpacing) {
29-
ForEach(months, id: \.monthStart) { month in
30-
WidgetHeatmapMonthGrid(
31-
month: month,
32-
layout: layout,
33-
selectedActivityKindRawValues: selectedActivityKindRawValues,
34-
maxCount: maxCount,
35-
showsMonthTitle: showsMonthTitles
36-
)
37-
}
25+
HStack(alignment: .top, spacing: layout.monthSpacing) {
26+
ForEach(months, id: \.monthStart) { month in
27+
WidgetHeatmapMonthGrid(
28+
month: month,
29+
layout: layout,
30+
selectedActivityKindRawValues: selectedActivityKindRawValues,
31+
maxCount: maxCount,
32+
showsMonthTitle: showsMonthTitles
33+
)
3834
}
3935
}
4036
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
@@ -71,45 +67,6 @@ struct WidgetHeatmapPlaceholderGrid: View {
7167
}
7268
}
7369

74-
private struct WidgetHeatmapWeekdayLabels: View {
75-
let layout: WidgetHeatmapLayout
76-
private let orderedWeekdays = Array(1...7)
77-
private let weekdayLabels = [
78-
2: "",
79-
4: "",
80-
6: ""
81-
]
82-
83-
var body: some View {
84-
VStack(alignment: .leading, spacing: layout.cellSpacing) {
85-
ForEach(orderedWeekdays, id: \.self) { weekday in
86-
weekdayLabel(for: weekday)
87-
}
88-
}
89-
.padding(.top, layout.weekdayTopPadding)
90-
}
91-
92-
@ViewBuilder
93-
private func weekdayLabel(for weekday: Int) -> some View {
94-
if let label = weekdayLabels[weekday] {
95-
Text(label)
96-
.font(.caption2)
97-
.foregroundStyle(.secondary)
98-
.frame(
99-
width: layout.weekdayLabelWidth,
100-
height: layout.cellSize,
101-
alignment: .leading
102-
)
103-
} else {
104-
Color.clear
105-
.frame(
106-
width: layout.weekdayLabelWidth,
107-
height: layout.cellSize
108-
)
109-
}
110-
}
111-
}
112-
11370
private struct WidgetHeatmapMonthGrid: View {
11471
let month: WidgetHeatmapMonthSnapshot
11572
let layout: WidgetHeatmapLayout

DevLogWidget/Heatmap/WidgetHeatmapLayout.swift

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@ struct WidgetHeatmapLayout {
1212
let cellSpacing: CGFloat
1313
let monthSpacing: CGFloat
1414
let monthTitleSpacing: CGFloat
15-
let weekdayLabelSpacing: CGFloat = Self.baseWeekdayLabelSpacing
16-
let weekdayLabelWidth: CGFloat = Self.baseWeekdayLabelWidth
1715
let showsMonthTitles: Bool
1816

1917
init(
@@ -37,10 +35,6 @@ struct WidgetHeatmapLayout {
3735
)
3836
}
3937

40-
var weekdayTopPadding: CGFloat {
41-
showsMonthTitles ? cellSize + monthTitleSpacing : 0
42-
}
43-
4438
var cellCornerRadius: CGFloat {
4539
max(2, cellSize * 0.2)
4640
}
@@ -49,8 +43,6 @@ struct WidgetHeatmapLayout {
4943
private static let baseMonthSpacing: CGFloat = 10
5044
private static let maxMonthSpacing: CGFloat = 26
5145
private static let baseMonthTitleSpacing: CGFloat = 4
52-
private static let baseWeekdayLabelSpacing: CGFloat = 5
53-
private static let baseWeekdayLabelWidth: CGFloat = 14
5446

5547
private static func resolvedMonthTitleSpacing(showsMonthTitles: Bool) -> CGFloat {
5648
// 월 제목을 표시하는 Medium에서만 제목과 셀 사이 간격을 확보한다.
@@ -99,10 +91,8 @@ struct WidgetHeatmapLayout {
9991
) -> CGFloat {
10092
// 셀 크기는 높이 기준으로 고정하고, 남는 가로폭만 월 간격 계산에 사용한다.
10193
let sanitizedWeekCounts = sanitizedWeekCounts(weekCounts)
102-
// 요일 라벨 영역, 전체 셀 컬럼, 월 내부 주차 spacing을 더해 기본 너비를 구한다.
103-
let contentWidth = baseWeekdayLabelWidth
104-
+ baseWeekdayLabelSpacing
105-
+ cellSize * CGFloat(totalColumns(in: sanitizedWeekCounts))
94+
// 전체 셀 컬럼과 월 내부 주차 spacing을 더해 기본 너비를 구한다.
95+
let contentWidth = cellSize * CGFloat(totalColumns(in: sanitizedWeekCounts))
10696
+ baseCellSpacing * CGFloat(totalColumnSpacings(in: sanitizedWeekCounts))
10797
// 기본 너비보다 위젯이 넓을 때만 월 간격에 분배할 여유 폭이 생긴다.
10898
return max(0, availableWidth - contentWidth)
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
{
2+
"sourceLanguage" : "ko",
3+
"strings" : {
4+
"#%lld" : {
5+
6+
},
7+
"%lld" : {
8+
9+
},
10+
"Heatmap" : {
11+
12+
},
13+
"Today" : {
14+
15+
},
16+
"widget_heatmap_current_month_title" : {
17+
"extractionState" : "manual",
18+
"localizations" : {
19+
"en" : {
20+
"stringUnit" : {
21+
"state" : "translated",
22+
"value" : "This Month"
23+
}
24+
},
25+
"ko" : {
26+
"stringUnit" : {
27+
"state" : "translated",
28+
"value" : "이번 달 히트맵"
29+
}
30+
}
31+
}
32+
},
33+
"widget_heatmap_current_quarter_title" : {
34+
"extractionState" : "manual",
35+
"localizations" : {
36+
"en" : {
37+
"stringUnit" : {
38+
"state" : "translated",
39+
"value" : "This Quarter"
40+
}
41+
},
42+
"ko" : {
43+
"stringUnit" : {
44+
"state" : "translated",
45+
"value" : "이번 분기 히트맵"
46+
}
47+
}
48+
}
49+
},
50+
"widget_heatmap_description" : {
51+
"extractionState" : "manual",
52+
"localizations" : {
53+
"en" : {
54+
"stringUnit" : {
55+
"state" : "translated",
56+
"value" : "Shows your activity heatmap."
57+
}
58+
},
59+
"ko" : {
60+
"stringUnit" : {
61+
"state" : "translated",
62+
"value" : "활동 히트맵을 표시합니다."
63+
}
64+
}
65+
}
66+
},
67+
"widget_today_description" : {
68+
"extractionState" : "manual",
69+
"localizations" : {
70+
"en" : {
71+
"stringUnit" : {
72+
"state" : "translated",
73+
"value" : "Shows today's Todo list."
74+
}
75+
},
76+
"ko" : {
77+
"stringUnit" : {
78+
"state" : "translated",
79+
"value" : "오늘 기준 Todo 목록을 표시합니다."
80+
}
81+
}
82+
}
83+
},
84+
"widget_today_empty_message" : {
85+
"extractionState" : "manual",
86+
"localizations" : {
87+
"en" : {
88+
"stringUnit" : {
89+
"state" : "translated",
90+
"value" : "No tasks for today.\nTake a short break!"
91+
}
92+
},
93+
"ko" : {
94+
"stringUnit" : {
95+
"state" : "translated",
96+
"value" : "오늘은 할 일이 없어요.\n잠시 휴식을 취해보세요!"
97+
}
98+
}
99+
}
100+
}
101+
},
102+
"version" : "1.0"
103+
}

0 commit comments

Comments
 (0)