Browse Source

Internationalize time ago since string

Switches to using standard date component formatting abbreviations and
enables it to be localized to non-English locales

Closes: #194
Changelog-Changed: Internationalize relative dates
post-button-style
Terry Yiu 2 years ago
committed by William Casarin
parent
commit
0b27a49e32
  1. 4
      damus.xcodeproj/project.pbxproj
  2. 29
      damus/Util/TimeAgo.swift
  3. 34
      damusTests/TimeAgoTests.swift

4
damus.xcodeproj/project.pbxproj

@ -11,6 +11,7 @@
3169CAE6294E69C000EE4006 /* EmptyTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3169CAE5294E69C000EE4006 /* EmptyTimelineView.swift */; };
3169CAED294FCCFC00EE4006 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3169CAEC294FCCFC00EE4006 /* Constants.swift */; };
31D2E847295218AF006D67F8 /* Shimmer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31D2E846295218AF006D67F8 /* Shimmer.swift */; };
3ACBCB78295FE5C70037388A /* TimeAgoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3ACBCB77295FE5C70037388A /* TimeAgoTests.swift */; };
4C06670128FC7C5900038D2A /* RelayView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C06670028FC7C5900038D2A /* RelayView.swift */; };
4C06670428FC7EC500038D2A /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = 4C06670328FC7EC500038D2A /* Kingfisher */; };
4C06670628FCB08600038D2A /* ImageCarousel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C06670528FCB08600038D2A /* ImageCarousel.swift */; };
@ -162,6 +163,7 @@
3169CAE5294E69C000EE4006 /* EmptyTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyTimelineView.swift; sourceTree = "<group>"; };
3169CAEC294FCCFC00EE4006 /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Constants.swift; path = damus/Util/Constants.swift; sourceTree = SOURCE_ROOT; };
31D2E846295218AF006D67F8 /* Shimmer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Shimmer.swift; sourceTree = "<group>"; };
3ACBCB77295FE5C70037388A /* TimeAgoTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeAgoTests.swift; sourceTree = "<group>"; };
4C06670028FC7C5900038D2A /* RelayView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayView.swift; sourceTree = "<group>"; };
4C06670528FCB08600038D2A /* ImageCarousel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageCarousel.swift; sourceTree = "<group>"; };
4C06670828FDE64700038D2A /* damus-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "damus-Bridging-Header.h"; sourceTree = "<group>"; };
@ -608,6 +610,7 @@
4C363A9D2828A822006E126D /* ReplyTests.swift */,
4CE6DEF727F7A08200C66700 /* damusTests.swift */,
4C3EA67A28FF7B3900C48A62 /* InvoiceTests.swift */,
3ACBCB77295FE5C70037388A /* TimeAgoTests.swift */,
);
path = damusTests;
sourceTree = "<group>";
@ -898,6 +901,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
3ACBCB78295FE5C70037388A /* TimeAgoTests.swift in Sources */,
4C3EA67B28FF7B3900C48A62 /* InvoiceTests.swift in Sources */,
4C363A9E2828A822006E126D /* ReplyTests.swift in Sources */,
4C363AA02828A8DD006E126D /* LikeTests.swift in Sources */,

29
damus/Util/TimeAgo.swift

@ -11,36 +11,45 @@ public func time_ago_since(_ date: Date) -> String {
let calendar = Calendar.current
let now = Date()
let unitFlags: NSCalendar.Unit = [.second, .minute, .hour, .day, .weekOfYear, .month, .year]
let unitFlags: NSCalendar.Unit = [.second, .minute, .hour, .day, .weekOfMonth, .month, .year]
let components = (calendar as NSCalendar).components(unitFlags, from: date, to: now, options: [])
let formatter = DateComponentsFormatter()
formatter.unitsStyle = .abbreviated
formatter.maximumUnitCount = 1
formatter.allowedUnits = unitFlags
// Manually format date component from only the most significant time unit because
// DateComponentsFormatter rounds up by default.
if let year = components.year, year >= 1 {
return "\(year)yr"
return formatter.string(from: DateComponents(calendar: calendar, year: year))!
}
if let month = components.month, month >= 1 {
return "\(month)mth"
return formatter.string(from: DateComponents(calendar: calendar, month: month))!
}
if let week = components.weekOfYear, week >= 1 {
return "\(week)wk"
if let week = components.weekOfMonth, week >= 1 {
return formatter.string(from: DateComponents(calendar: calendar, weekOfMonth: week))!
}
if let day = components.day, day >= 1 {
return "\(day)d"
return formatter.string(from: DateComponents(calendar: calendar, day: day))!
}
if let hour = components.hour, hour >= 1 {
return "\(hour)h"
return formatter.string(from: DateComponents(calendar: calendar, hour: hour))!
}
if let minute = components.minute, minute >= 1 {
return "\(minute)m"
return formatter.string(from: DateComponents(calendar: calendar, minute: minute))!
}
if let second = components.second, second >= 3 {
return "\(second)s"
return formatter.string(from: DateComponents(calendar: calendar, second: second))!
}
return "now"
return NSLocalizedString("now", comment: "String indicating that a given timestamp just occurred")
}

34
damusTests/TimeAgoTests.swift

@ -0,0 +1,34 @@
//
// TimeAgoTests.swift
// damusTests
//
// Created by Terry Yiu on 12/30/22.
//
import XCTest
@testable import damus
final class TimeAgoTests: XCTestCase {
func testTimeAgoSince() {
XCTAssertEqual(time_ago_since(Date.now), "now")
XCTAssertEqual(time_ago_since(Date.now.addingTimeInterval(-2)), "now")
XCTAssertEqual(time_ago_since(Date.now.addingTimeInterval(-3)), "3s")
XCTAssertEqual(time_ago_since(Date.now.addingTimeInterval(-59)), "59s")
XCTAssertEqual(time_ago_since(Date.now.addingTimeInterval(-60)), "1m")
XCTAssertEqual(time_ago_since(Date.now.addingTimeInterval(-3599)), "59m")
XCTAssertEqual(time_ago_since(Date.now.addingTimeInterval(-3600)), "1h")
XCTAssertEqual(time_ago_since(Date.now.addingTimeInterval(-86399)), "23h")
XCTAssertEqual(time_ago_since(Date.now.addingTimeInterval(-86400)), "1d")
XCTAssertEqual(time_ago_since(Calendar.current.date(byAdding: .weekOfMonth, value: -1, to: Date.now)!.addingTimeInterval(1)), "6d")
XCTAssertEqual(time_ago_since(Calendar.current.date(byAdding: .weekOfMonth, value: -1, to: Date.now)!), "1w")
XCTAssertEqual(time_ago_since(Calendar.current.date(byAdding: .weekOfMonth, value: -2, to: Date.now)!), "2w")
XCTAssertEqual(time_ago_since(Calendar.current.date(byAdding: .weekOfMonth, value: -3, to: Date.now)!), "3w")
// Not testing the 4-5 week boundary since how it is formatted depends on which month and year it is currently when this test executes.
XCTAssertEqual(time_ago_since(Calendar.current.date(byAdding: .month, value: -1, to: Date.now)!), "1mo")
XCTAssertEqual(time_ago_since(Calendar.current.date(byAdding: .year, value: -1, to: Date.now)!.addingTimeInterval(1)), "11mo")
XCTAssertEqual(time_ago_since(Calendar.current.date(byAdding: .year, value: -1, to: Date.now)!), "1y")
XCTAssertEqual(time_ago_since(Calendar.current.date(byAdding: .year, value: -1000, to: Date.now)!), "1,000y")
}
}
Loading…
Cancel
Save