diff --git a/Lin/LNAlertAccessoryView.h b/Lin/LNAlertAccessoryView.h
index 3df161d..355988a 100644
--- a/Lin/LNAlertAccessoryView.h
+++ b/Lin/LNAlertAccessoryView.h
@@ -18,5 +18,6 @@
@property (nonatomic, copy, readonly) LNLocalizationCollection *selectedCollection;
@property (nonatomic, copy, readonly) NSString *inputtedKey;
@property (nonatomic, copy, readonly) NSString *inputtedValue;
+@property (nonatomic, copy, readonly) NSString *inputtedComment;
@end
diff --git a/Lin/LNAlertAccessoryView.m b/Lin/LNAlertAccessoryView.m
index 78b1c14..fb3658c 100644
--- a/Lin/LNAlertAccessoryView.m
+++ b/Lin/LNAlertAccessoryView.m
@@ -17,6 +17,7 @@ @interface LNAlertAccessoryView ()
@property (weak) IBOutlet NSPopUpButton *languageButton;
@property (weak) IBOutlet NSTextField *keyTextField;
@property (weak) IBOutlet NSTextField *valueTextField;
+@property (weak) IBOutlet NSTextField *commentTextField;
@end
@@ -71,6 +72,10 @@ - (NSString *)inputtedValue
return self.valueTextField.stringValue;
}
+- (NSString *)inputtedComment
+{
+ return self.commentTextField.stringValue;
+}
#pragma mark - Actions
@@ -123,6 +128,7 @@ - (void)configureButton
{
NSString *key = self.keyTextField.stringValue;
NSString *value = self.valueTextField.stringValue;
+ // comment is optional
[self.button setEnabled:(self.collections.count > 0 && key.length > 0 && value.length > 0)];
}
diff --git a/Lin/LNAlertAccessoryView.xib b/Lin/LNAlertAccessoryView.xib
index 4ee3fe0..f6075c4 100644
--- a/Lin/LNAlertAccessoryView.xib
+++ b/Lin/LNAlertAccessoryView.xib
@@ -1,8 +1,8 @@
-
+
-
-
+
+
@@ -13,11 +13,11 @@
-
+
-
+
@@ -26,7 +26,7 @@
-
+
@@ -35,7 +35,7 @@
-
+
@@ -44,7 +44,7 @@
-
+
@@ -52,8 +52,17 @@
+
+
+
+
+
+
+
+
+
-
+
@@ -71,7 +80,7 @@
-
+
@@ -86,7 +95,7 @@
-
+
@@ -98,7 +107,7 @@
-
+
@@ -109,8 +118,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -118,4 +140,4 @@
-
\ No newline at end of file
+
diff --git a/Lin/LNLocalization.h b/Lin/LNLocalization.h
index 147dd85..c4de6fe 100644
--- a/Lin/LNLocalization.h
+++ b/Lin/LNLocalization.h
@@ -14,6 +14,7 @@
@property (nonatomic, copy, readonly) NSString *key;
@property (nonatomic, copy, readonly) NSString *value;
+@property (nonatomic, copy, readonly) NSString *comment;
@property (nonatomic, assign, readonly) NSRange entityRange;
@property (nonatomic, assign, readonly) NSRange keyRange;
@@ -21,8 +22,8 @@
@property (nonatomic, weak, readonly) LNLocalizationCollection *collection;
-+ (instancetype)localizationWithKey:(NSString *)key value:(NSString *)value entityRange:(NSRange)entityRange keyRange:(NSRange)keyRange valueRange:(NSRange)valueRange collection:(LNLocalizationCollection *)collection;
++ (instancetype)localizationWithKey:(NSString *)key value:(NSString *)value comment:(NSString *)comment entityRange:(NSRange)entityRange keyRange:(NSRange)keyRange valueRange:(NSRange)valueRange collection:(LNLocalizationCollection *)collection;
-- (instancetype)initWithKey:(NSString *)key value:(NSString *)value entityRange:(NSRange)entityRange keyRange:(NSRange)keyRange valueRange:(NSRange)valueRange collection:(LNLocalizationCollection *)collection;
+- (instancetype)initWithKey:(NSString *)key value:(NSString *)value comment:(NSString *)comment entityRange:(NSRange)entityRange keyRange:(NSRange)keyRange valueRange:(NSRange)valueRange collection:(LNLocalizationCollection *)collection;
@end
diff --git a/Lin/LNLocalization.m b/Lin/LNLocalization.m
index 411f0cf..683432f 100644
--- a/Lin/LNLocalization.m
+++ b/Lin/LNLocalization.m
@@ -12,6 +12,7 @@ @interface LNLocalization ()
@property (nonatomic, copy, readwrite) NSString *key;
@property (nonatomic, copy, readwrite) NSString *value;
+@property (nonatomic, copy, readwrite) NSString *comment;
@property (nonatomic, assign, readwrite) NSRange entityRange;
@property (nonatomic, assign, readwrite) NSRange keyRange;
@@ -23,18 +24,19 @@ @interface LNLocalization ()
@implementation LNLocalization
-+ (instancetype)localizationWithKey:(NSString *)key value:(NSString *)value entityRange:(NSRange)entityRange keyRange:(NSRange)keyRange valueRange:(NSRange)valueRange collection:(LNLocalizationCollection *)collection
++ (instancetype)localizationWithKey:(NSString *)key value:(NSString *)value comment:(NSString *)comment entityRange:(NSRange)entityRange keyRange:(NSRange)keyRange valueRange:(NSRange)valueRange collection:(LNLocalizationCollection *)collection
{
- return [[self alloc] initWithKey:key value:value entityRange:(NSRange)entityRange keyRange:keyRange valueRange:valueRange collection:collection];
+ return [[self alloc] initWithKey:key value:value comment:comment entityRange:(NSRange)entityRange keyRange:keyRange valueRange:valueRange collection:collection];
}
-- (instancetype)initWithKey:(NSString *)key value:(NSString *)value entityRange:(NSRange)entityRange keyRange:(NSRange)keyRange valueRange:(NSRange)valueRange collection:(LNLocalizationCollection *)collection
+- (instancetype)initWithKey:(NSString *)key value:(NSString *)value comment:(NSString *)comment entityRange:(NSRange)entityRange keyRange:(NSRange)keyRange valueRange:(NSRange)valueRange collection:(LNLocalizationCollection *)collection
{
self = [super init];
if (self) {
self.key = key;
self.value = value;
+ self.comment = comment;
self.entityRange = entityRange;
self.keyRange = keyRange;
@@ -66,11 +68,12 @@ - (NSUInteger)hash
- (NSString *)description
{
return [NSString stringWithFormat:
- @"<%@: %p; key = %@; value = %@; entityRange = %@; keyRange = %@; valueRange = %@; collection = %p>",
+ @"<%@: %p; key = %@; value = %@; comment = %@; entityRange = %@; keyRange = %@; valueRange = %@; collection = %p>",
NSStringFromClass([self class]),
self,
self.key,
self.value,
+ self.comment,
NSStringFromRange(self.entityRange),
NSStringFromRange(self.keyRange),
NSStringFromRange(self.valueRange),
diff --git a/Lin/LNLocalizationCollection.m b/Lin/LNLocalizationCollection.m
index 2c786d5..64462d1 100644
--- a/Lin/LNLocalizationCollection.m
+++ b/Lin/LNLocalizationCollection.m
@@ -36,7 +36,10 @@ - (instancetype)initWithContentsOfFile:(NSString *)filePath
// Extract language designation
NSArray *pathComponents = [filePath pathComponents];
- self.languageDesignation = [[pathComponents objectAtIndex:pathComponents.count - 2] stringByDeletingPathExtension];
+ // The superdir is shown in parentheses to distinguish possible duplicate name-language combos
+ self.languageDesignation = [NSString stringWithFormat:@"%@ (%@)",
+ [[pathComponents objectAtIndex:pathComponents.count - 2] stringByDeletingPathExtension],
+ [pathComponents objectAtIndex:pathComponents.count - 3]];
// Update
[self reloadLocalizations];
@@ -93,59 +96,44 @@ - (void)reloadLocalizations
if (contents) {
NSMutableSet *localizations = [NSMutableSet set];
- // Parse
- __block NSInteger lineOffset = 0;
- __block NSString *key;
- __block NSString *value;
- __block NSRange entityRange;
- __block NSRange keyRange;
- __block NSRange valueRange;
+ // to keep it simple for now comments are only accepted if
+ // * the comment is C-style
+ // * the comment is on the line above the key-value
+ // * the comment is followed by no whitespace except one new line
+ // * the key-value line is not prefixed with any whitespace
+ // this can be changed later on when time allows :)
+ // example found below:
+ // v - no whitespace here except newline
+ // /* Comment */
+ // @"key" = @"value";
+ // ^ - no whitespace here
- NSRegularExpression *regularExpression = [NSRegularExpression regularExpressionWithPattern:@"(\"(\\S+.*\\S+)\"|(\\S+.*\\S+))\\s*=\\s*\"(.*)\";$"
+ NSRegularExpression *regularExpression = [NSRegularExpression regularExpressionWithPattern:
+ @"(?#comment)(?:/\\*(.*)\\*/\n)?"
+ @"(?#key )(?:\"(.*)\"|(\\S+))"
+ @"(?#equals )\\s*=\\s*"
+ @"(?#value )\"(.*)\";"
options:0
- error:NULL];
+ error:nil];
- [contents enumerateLinesUsingBlock:^(NSString *line, BOOL *stop) {
- key = nil;
- value = nil;
- keyRange = NSMakeRange(NSNotFound, 0);
- valueRange = NSMakeRange(NSNotFound, 0);
+ [regularExpression enumerateMatchesInString:contents options:0 range:NSMakeRange(0, [contents length]) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
+ NSString *comment = nil;
- NSTextCheckingResult *result = [regularExpression firstMatchInString:line
- options:0
- range:NSMakeRange(0, line.length)];
+ NSRange entityRange = [result rangeAtIndex:0];
+ NSRange commentRange = [result rangeAtIndex:1];
+ NSRange keyRange = [result rangeAtIndex:2].location != NSNotFound ? [result rangeAtIndex:2] : [result rangeAtIndex:3];
+ NSRange valueRange = [result rangeAtIndex:4];
- if (result.range.location != NSNotFound && result.numberOfRanges == 5) {
- entityRange = [result rangeAtIndex:0];
- entityRange.location += lineOffset;
-
- keyRange = [result rangeAtIndex:2];
- if (keyRange.location == NSNotFound) keyRange = [result rangeAtIndex:3];
-
- valueRange = [result rangeAtIndex:4];
-
- key = [line substringWithRange:keyRange];
- value = [line substringWithRange:valueRange];
-
- keyRange.location += lineOffset;
- valueRange.location += lineOffset;
- }
+ if (commentRange.location != NSNotFound)
+ comment = [contents substringWithRange:commentRange];
- // Create localization
- if (key != nil && value != nil) {
- LNLocalization *localization = [LNLocalization localizationWithKey:key
- value:value
- entityRange:entityRange
- keyRange:keyRange
- valueRange:valueRange
- collection:self];
-
- [localizations addObject:localization];
- }
-
- // Move offset
- NSRange lineRange = [contents lineRangeForRange:NSMakeRange(lineOffset, 0)];
- lineOffset += lineRange.length;
+ [localizations addObject:[LNLocalization localizationWithKey:[contents substringWithRange:keyRange]
+ value:[contents substringWithRange:valueRange]
+ comment:comment
+ entityRange:entityRange
+ keyRange:keyRange
+ valueRange:valueRange
+ collection:self]];
}];
self.localizations = localizations;
@@ -154,70 +142,79 @@ - (void)reloadLocalizations
}
}
-- (void)addLocalization:(LNLocalization *)localization
+- (NSString *)formatEntity:(LNLocalization *)localization
{
- // Load contents
- NSString *contents = [self loadContentsOfFile:self.filePath];
+ NSString *comment = @"";
- // Add
- if (![contents hasSuffix:@"\n"]) {
- contents = [contents stringByAppendingString:@"\n"];
+ if (localization.comment && [localization.comment length] > 0) {
+ // Add spaces at the ends if needed
+ NSString *prefix = [localization.comment hasPrefix:@" "] ? @"" : @" ";
+ NSString *suffix = [localization.comment hasSuffix:@" "] ? @"" : @" ";
+
+ comment = [NSString stringWithFormat:@"/*%@%@%@*/\n", prefix, localization.comment, suffix];
}
- contents = [contents stringByAppendingFormat:@"\"%@\" = \"%@\";\n", localization.key, localization.value];
-
+ return [NSString stringWithFormat:@"%@\"%@\" = \"%@\";", comment, localization.key, localization.value];
+}
+
+- (void)writeContents:(NSString *)contents withRange:(NSRange)range replacedWithString:(NSString *)string
+{
// Override
NSError *error = nil;
- [contents writeToFile:self.filePath atomically:NO encoding:NSUTF8StringEncoding error:&error];
+ [[contents stringByReplacingCharactersInRange:range withString:string] writeToFile:self.filePath atomically:NO encoding:NSUTF8StringEncoding error:&error];
if (error) {
NSLog(@"Error: %@", [error localizedDescription]);
}
-
+
// Reload
[self reloadLocalizations];
}
-- (void)deleteLocalization:(LNLocalization *)localization
+- (void)addLocalization:(LNLocalization *)localization
{
// Load contents
NSString *contents = [self loadContentsOfFile:self.filePath];
+ __block NSRange range = NSMakeRange([contents length], 0); // Starting point if no trailing white space found
- // Delete line
- NSRange lineRange = [contents lineRangeForRange:localization.entityRange];
- contents = [contents stringByReplacingCharactersInRange:lineRange withString:@""];
+ NSRegularExpression *regularExpression = [NSRegularExpression regularExpressionWithPattern:
+ @"(?#capture trailing whitespace)(\\s+)$"
+ options:0
+ error:nil];
- // Override
- NSError *error = nil;
- [contents writeToFile:self.filePath atomically:NO encoding:NSUTF8StringEncoding error:&error];
+ [regularExpression enumerateMatchesInString:contents options:0 range:NSMakeRange(0, [contents length]) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
+ range = [result rangeAtIndex:1];
+ }];
- if (error) {
- NSLog(@"Error: %@", [error localizedDescription]);
- }
-
- // Reload
- [self reloadLocalizations];
+ [self writeContents:contents withRange:range replacedWithString:[NSString stringWithFormat:@"\n\n%@\n", [self formatEntity:localization]]];
}
-- (void)replaceLocalization:(LNLocalization *)localization withLocalization:(LNLocalization *)newLocalization
+- (void)deleteLocalization:(LNLocalization *)localization
{
+ NSCharacterSet *whitespace = [NSCharacterSet whitespaceAndNewlineCharacterSet];
+
// Load contents
NSString *contents = [self loadContentsOfFile:self.filePath];
- // Replace
- NSString *newEntity = [NSString stringWithFormat:@"\"%@\" = \"%@\";", newLocalization.key, newLocalization.value];
- contents = [contents stringByReplacingCharactersInRange:localization.entityRange withString:newEntity];
+ NSRange range = localization.entityRange; // Starting point
- // Override
- NSError *error = nil;
- [contents writeToFile:self.filePath atomically:NO encoding:NSUTF8StringEncoding error:&error];
+ // Expand range left if whitespace is present
+ while (range.location > 0 && [whitespace characterIsMember:[contents characterAtIndex:range.location - 1]]) {
+ range.location--;
+ range.length++;
+ }
- if (error) {
- NSLog(@"Error: %@", [error localizedDescription]);
+ // Expand range right if whitespace is present
+ while (NSMaxRange(range) < [contents length] && [whitespace characterIsMember:[contents characterAtIndex:NSMaxRange(range)]]) {
+ range.length++;
}
- // Reload
- [self reloadLocalizations];
+ [self writeContents:[self loadContentsOfFile:self.filePath] withRange:range replacedWithString:@"\n\n"];
+}
+
+- (void)replaceLocalization:(LNLocalization *)localization withLocalization:(LNLocalization *)newLocalization
+{
+ [self writeContents:[self loadContentsOfFile:self.filePath] withRange:localization.entityRange replacedWithString:[self formatEntity:newLocalization]];
}
@end
diff --git a/Lin/LNPopoverContentView.m b/Lin/LNPopoverContentView.m
index 65f6129..5cb2165 100644
--- a/Lin/LNPopoverContentView.m
+++ b/Lin/LNPopoverContentView.m
@@ -110,6 +110,7 @@ - (void)textDidEndEditing:(NSNotification *)notification
NSString *key = localization.key;
NSString *value = localization.value;
+ NSString *comment = localization.comment;
NSString *columnIdentifier = [self.tableView editedColumnIdentifier];
@@ -117,10 +118,13 @@ - (void)textDidEndEditing:(NSNotification *)notification
key = textView.textStorage.string;
} else if ([columnIdentifier isEqualToString:@"value"]) {
value = textView.textStorage.string;
+ } else if ([columnIdentifier isEqualToString:@"comment"]) {
+ comment = textView.textStorage.string;
}
-
+
LNLocalization *newLocalization = [LNLocalization localizationWithKey:key
value:value
+ comment:comment
entityRange:localization.entityRange
keyRange:localization.keyRange
valueRange:localization.valueRange
@@ -184,9 +188,11 @@ - (IBAction)addLocalization:(id)sender
LNLocalizationCollection *collection = accessoryView.selectedCollection;
NSString *key = accessoryView.inputtedKey;
NSString *value = accessoryView.inputtedValue;
+ NSString *comment = accessoryView.inputtedComment;
LNLocalization *localization = [LNLocalization localizationWithKey:key
value:value
+ comment:comment
entityRange:NSMakeRange(NSNotFound, 0)
keyRange:NSMakeRange(NSNotFound, 0)
valueRange:NSMakeRange(NSNotFound, 0)
@@ -309,6 +315,9 @@ - (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColum
else if ([identifier isEqualToString:@"value"]) {
return localization.value;
}
+ else if ([identifier isEqualToString:@"comment"]) {
+ return localization.comment;
+ }
return nil;
}
diff --git a/Lin/LNPopoverContentView.xib b/Lin/LNPopoverContentView.xib
index aeaa319..a6b5e8b 100644
--- a/Lin/LNPopoverContentView.xib
+++ b/Lin/LNPopoverContentView.xib
@@ -1,8 +1,8 @@
-
+
-
+
@@ -12,19 +12,19 @@
-
-
+
+
-
+
-
+
-
+
@@ -87,6 +87,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -97,7 +111,7 @@
-
+
@@ -105,22 +119,22 @@
-
+
-
+
-
+
-
+
\ No newline at end of file
+
diff --git a/LinTests/LNLocalizationTests.m b/LinTests/LNLocalizationTests.m
index 2f54f6b..779fc4f 100644
--- a/LinTests/LNLocalizationTests.m
+++ b/LinTests/LNLocalizationTests.m
@@ -67,6 +67,7 @@ - (void)testParsingPatterns
for (NSInteger i = 0; i < numberOfTestSets; i++) {
LNLocalization *localization = [LNLocalization localizationWithKey:testSets[i].key
value:testSets[i].value
+ comment:nil
entityRange:NSMakeRange(0, 0)
keyRange:NSMakeRange(0, 0)
valueRange:NSMakeRange(0, 0)