Refresh interval string localizations

This commit is contained in:
relikd
2019-07-08 22:40:16 +02:00
parent 31e0821080
commit dda219b570
10 changed files with 75 additions and 91 deletions

View File

@@ -39,8 +39,10 @@ typedef NS_ENUM(int32_t, TimeUnitType) {
@interface NSDate (Interval)
+ (nonnull NSString*)stringForInterval:(Interval)intv rounded:(BOOL)flag;
+ (TimeUnitType)unitForInterval:(Interval)intv rounded:(BOOL)flag;
+ (nullable NSString*)intStringForInterval:(Interval)intv;
+ (nonnull NSString*)floatStringForInterval:(Interval)intv;
+ (nullable NSString*)stringForRemainingTime:(NSDate*)other;
+ (Interval)floatToIntInterval:(Interval)intv;
@end

View File

@@ -24,8 +24,6 @@
#import <QuartzCore/QuartzCore.h>
static const char _shortnames[] = {'y','w','d','h','m','s'};
static const char *_names[] = {"Years", "Weeks", "Days", "Hours", "Minutes", "Seconds"};
static const TimeUnitType _values[] = {
TimeUnitYears,
TimeUnitWeeks,
@@ -55,61 +53,58 @@ static const TimeUnitType _values[] = {
@implementation NSDate (Interval)
/// If @c flag @c = @c YES, print @c 1.1f float string with single char unit: e.g., 3.3m, 1.7h.
+ (nonnull NSString*)stringForInterval:(Interval)intv rounded:(BOOL)flag {
if (flag) {
unsigned short i = [self floatUnitIndexForInterval:abs(intv)];
return [NSString stringWithFormat:@"%1.1f%c", intv / (float)_values[i], _shortnames[i]];
/// Short interval formatter string (e.g., '30 min', '2 hrs')
+ (nullable NSString*)intStringForInterval:(Interval)intv {
TimeUnitType unit = [self unitForInterval:intv];
Interval num = intv / unit;
NSDateComponents *dc = [[NSDateComponents alloc] init];
switch (unit) {
case TimeUnitSeconds: dc.second = num; break;
case TimeUnitMinutes: dc.minute = num; break;
case TimeUnitHours: dc.hour = num; break;
case TimeUnitDays: dc.day = num; break;
case TimeUnitWeeks: dc.weekOfMonth = num; break;
case TimeUnitYears: dc.year = num; break;
}
unsigned short i = [self exactUnitIndexForInterval:abs(intv)];
return [NSString stringWithFormat:@"%d%c", intv / _values[i], _shortnames[i]];
return [NSDateComponentsFormatter localizedStringFromDateComponents:dc unitsStyle:NSDateComponentsFormatterUnitsStyleShort];
}
/// @return Highest non-zero unit ( @c flag=YES ). Or highest integer-dividable unit ( @c flag=NO ).
+ (TimeUnitType)unitForInterval:(Interval)intv rounded:(BOOL)flag {
if (flag) {
return _values[[self floatUnitIndexForInterval:abs(intv)]];
}
return _values[[self exactUnitIndexForInterval:abs(intv)]];
/// Print @c 1.1f float string with single char unit: e.g., 3.3m, 1.7h.
+ (nonnull NSString*)floatStringForInterval:(Interval)intv {
unsigned short i = [self floatUnitIndexForInterval:abs(intv)];
return [NSString stringWithFormat:@"%1.1f%c", intv / (float)_values[i], "ywdhms"[i]];
}
/// @return Highest unit type that allows integer division. E.g., '61 minutes'.
+ (unsigned short)exactUnitIndexForInterval:(Interval)intv {
for (unsigned short i = 0; i < 5; i++)
if (intv % _values[i] == 0) return i;
return 5; // seconds
/// Short interval formatter string for remaining time until @c other date
+ (nullable NSString*)stringForRemainingTime:(NSDate*)other {
NSDateComponentsFormatter *formatter = [[NSDateComponentsFormatter alloc] init];
formatter.unitsStyle = NSDateComponentsFormatterUnitsStyleShort; // e.g., '30 min'
formatter.maximumUnitCount = 1;
return [formatter stringFromTimeInterval: other.timeIntervalSinceNow];
}
/// Round uneven intervals to highest unit interval. E.g., @c 1:40>2:00 or @c 1:03>1:00
+ (Interval)floatToIntInterval:(Interval)intv {
TimeUnitType unit = _values[[self floatUnitIndexForInterval:abs(intv)]];
return (Interval)(roundf((float)intv / unit) * unit);
}
/// @return Highest integer-dividable unit. E.g., '61 minutes'
+ (TimeUnitType)unitForInterval:(Interval)intv {
if (intv == 0) return TimeUnitMinutes; // fallback to 0 minutes
for (unsigned short i = 0; i < 5; i++) // try: years -> minutes
if (intv % _values[i] == 0) return _values[i];
return TimeUnitSeconds;
}
/// @return Highest non-zero unit type. Can be used with fractions e.g., '1.1 hours'.
+ (unsigned short)floatUnitIndexForInterval:(Interval)intv {
if (intv == 0) return 4; // fallback to 0 minutes
for (unsigned short i = 0; i < 5; i++)
if (intv > _values[i]) return i;
return 5; // seconds
}
/* NOT USED
/// Convert any unit to the next smaller one. Unit does not have to be exact.
+ (TimeUnitType)smallerUnit:(TimeUnitType)unit {
if (unit <= TimeUnitHours) return TimeUnitSeconds;
if (unit <= TimeUnitDays) return TimeUnitMinutes; // > hours
if (unit <= TimeUnitWeeks) return TimeUnitHours; // > days
if (unit <= TimeUnitYears) return TimeUnitDays; // > weeks
return TimeUnitWeeks; // > years
}
/// @return Formatted string from @c timeIntervalSinceNow.
- (nonnull NSString*)intervalStringWithDecimal:(BOOL)flag {
return [NSDate stringForInterval:(Interval)[self timeIntervalSinceNow] rounded:flag];
}
/// @return Highest non-zero unit ( @c flag=YES ). Or highest integer-dividable unit ( @c flag=NO ).
- (TimeUnitType)unitWithDecimal:(BOOL)flag {
Interval absIntv = abs((Interval)[self timeIntervalSinceNow]);
if (flag) {
return _values[ [NSDate floatUnitIndexForInterval:absIntv] ];
}
return _values[ [NSDate exactUnitIndexForInterval:absIntv] ];
}
*/
@end
@@ -122,7 +117,7 @@ static const TimeUnitType _values[] = {
/// Configure both @c NSControl elements based on the provided interval @c intv.
+ (void)setInterval:(Interval)intv forPopup:(NSPopUpButton*)popup andField:(NSTextField*)field animate:(BOOL)flag {
TimeUnitType unit = [self unitForInterval:intv rounded:NO];
TimeUnitType unit = [self unitForInterval:intv];
int num = (int)(intv / unit);
if (flag && popup.selectedTag != unit) [self animateControlSize:popup];
if (flag && field.intValue != num) [self animateControlSize:field];
@@ -133,11 +128,12 @@ static const TimeUnitType _values[] = {
/// Insert all @c TimeUnitType items into popup button. Save unit value into @c tag attribute.
+ (void)populateUnitsMenu:(NSPopUpButton*)popup selected:(TimeUnitType)unit {
[popup removeAllItems];
for (NSUInteger i = 0; i < 6; i++) {
[popup addItemWithTitle:[NSString stringWithUTF8String:_names[i]]];
NSMenuItem *item = popup.lastItem;
[item setKeyEquivalent:[[NSString stringWithFormat:@"%c", _shortnames[i]] uppercaseString]];
item.tag = _values[i];
[popup addItemsWithTitles:@[NSLocalizedString(@"Years", nil), NSLocalizedString(@"Weeks", nil),
NSLocalizedString(@"Days", nil), NSLocalizedString(@"Hours", nil),
NSLocalizedString(@"Minutes", nil), NSLocalizedString(@"Seconds", nil)]];
for (int i = 0; i < 6; i++) {
[popup itemAtIndex:i].tag = _values[i];
[popup itemAtIndex:i].keyEquivalent = [NSString stringWithFormat:@"%d", i+1]; // Cmd+1 .. Cmd+6
}
[popup selectItemWithTag:unit];
}