aboutsummaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
authorrowanbeentje <rowan@beent.je>2010-06-12 15:20:57 +0000
committerrowanbeentje <rowan@beent.je>2010-06-12 15:20:57 +0000
commit1c89992b2af18acb457819b94f50fee247620d28 (patch)
tree7ab7503093ab37b96dd709a70a1180881d7a6fcd /Source
parent03bdabf809d02a7f76c2fbc02841bb1030c49a47 (diff)
downloadsequelpro-1c89992b2af18acb457819b94f50fee247620d28.tar.gz
sequelpro-1c89992b2af18acb457819b94f50fee247620d28.tar.bz2
sequelpro-1c89992b2af18acb457819b94f50fee247620d28.zip
- Implement the Wil shipley/Golden % Braeburn localisation method for .xibs; add a build stage to Release/Dist builds which generates .strings files for each nib, and swizzle nib loading to automatically translate strings based on any localised .strings files
- Fix the genstring stage of the build script and move it to Release/Dist builds only - Update Localizable.strings to match latest code
Diffstat (limited to 'Source')
-rw-r--r--Source/DMLocalizedNibBundle.m217
-rw-r--r--Source/xibLocalizationPostprocessor.m62
2 files changed, 279 insertions, 0 deletions
diff --git a/Source/DMLocalizedNibBundle.m b/Source/DMLocalizedNibBundle.m
new file mode 100644
index 00000000..e9200bc0
--- /dev/null
+++ b/Source/DMLocalizedNibBundle.m
@@ -0,0 +1,217 @@
+// DMLocalizedNibBundle.m
+//
+// Created by William Jon Shipley on 2/13/05.
+// Copyright © 2005-2009 Golden % Braeburn, LLC. All rights reserved except as below:
+// This code is provided as-is, with no warranties or anything. You may use it in your projects as you wish, but you must leave this comment block (credits and copyright) intact. That's the only restriction -- Golden % Braeburn otherwise grants you a fully-paid, worldwide, transferrable license to use this code as you see fit, including but not limited to making derivative works.
+
+
+#import <Cocoa/Cocoa.h>
+#import <objc/runtime.h>
+
+
+@interface NSBundle (DMLocalizedNibBundle)
++ (BOOL)deliciousLocalizingLoadNibFile:(NSString *)fileName externalNameTable:(NSDictionary *)context withZone:(NSZone *)zone;
+@end
+
+@interface NSBundle ()
++ (void)_localizeStringsInObject:(id)object table:(NSString *)table;
++ (NSString *)_localizedStringForString:(NSString *)string table:(NSString *)table;
+// localize particular attributes in objects
++ (void)_localizeTitleOfObject:(id)object table:(NSString *)table;
++ (void)_localizeAlternateTitleOfObject:(id)object table:(NSString *)table;
++ (void)_localizeStringValueOfObject:(id)object table:(NSString *)table;
++ (void)_localizePlaceholderStringOfObject:(id)object table:(NSString *)table;
++ (void)_localizeToolTipOfObject:(id)object table:(NSString *)table;
+@end
+
+
+@implementation NSBundle (DMLocalizedNibBundle)
+
+#pragma mark NSObject
+
++ (void)load;
+{
+ NSAutoreleasePool *autoreleasePool = [[NSAutoreleasePool alloc] init];
+ if (self == [NSBundle class]) {
+ method_exchangeImplementations(class_getClassMethod(self, @selector(loadNibFile:externalNameTable:withZone:)), class_getClassMethod(self, @selector(deliciousLocalizingLoadNibFile:externalNameTable:withZone:)));
+ }
+ [autoreleasePool release];
+}
+
+
+#pragma mark API
+
++ (BOOL)deliciousLocalizingLoadNibFile:(NSString *)fileName externalNameTable:(NSDictionary *)context withZone:(NSZone *)zone;
+{
+ NSString *localizedStringsTableName = [[fileName lastPathComponent] stringByDeletingPathExtension];
+ NSString *localizedStringsTablePath = [[NSBundle mainBundle] pathForResource:localizedStringsTableName ofType:@"strings"];
+ if (localizedStringsTablePath && ![[[localizedStringsTablePath stringByDeletingLastPathComponent] lastPathComponent] isEqualToString:@"English.lproj"]) {
+
+ NSNib *nib = [[NSNib alloc] initWithContentsOfURL:[NSURL fileURLWithPath:fileName]];
+ NSMutableArray *topLevelObjectsArray = [context objectForKey:NSNibTopLevelObjects];
+ if (!topLevelObjectsArray) {
+ topLevelObjectsArray = [NSMutableArray array];
+ context = [NSMutableDictionary dictionaryWithDictionary:context];
+ [(NSMutableDictionary *)context setObject:topLevelObjectsArray forKey:NSNibTopLevelObjects];
+ }
+ BOOL success = [nib instantiateNibWithExternalNameTable:context];
+ [self _localizeStringsInObject:topLevelObjectsArray table:localizedStringsTableName];
+
+ [nib release];
+ return success;
+
+ } else {
+ return [self deliciousLocalizingLoadNibFile:fileName externalNameTable:context withZone:zone];
+ }
+}
+
+
+
+#pragma mark Private API
+
++ (void)_localizeStringsInObject:(id)object table:(NSString *)table;
+{
+ if ([object isKindOfClass:[NSArray class]]) {
+ NSArray *array = object;
+
+ for (id nibItem in array)
+ [self _localizeStringsInObject:nibItem table:table];
+
+ } else if ([object isKindOfClass:[NSCell class]]) {
+ NSCell *cell = object;
+
+ if ([cell isKindOfClass:[NSActionCell class]]) {
+ NSActionCell *actionCell = (NSActionCell *)cell;
+
+ if ([actionCell isKindOfClass:[NSButtonCell class]]) {
+ NSButtonCell *buttonCell = (NSButtonCell *)actionCell;
+ if ([buttonCell imagePosition] != NSImageOnly) {
+ [self _localizeTitleOfObject:buttonCell table:table];
+ [self _localizeStringValueOfObject:buttonCell table:table];
+ [self _localizeAlternateTitleOfObject:buttonCell table:table];
+ }
+
+ } else if ([actionCell isKindOfClass:[NSTextFieldCell class]]) {
+ NSTextFieldCell *textFieldCell = (NSTextFieldCell *)actionCell;
+ // Following line is redundant with other code, localizes twice.
+ // [self _localizeTitleOfObject:textFieldCell table:table];
+ [self _localizeStringValueOfObject:textFieldCell table:table];
+ [self _localizePlaceholderStringOfObject:textFieldCell table:table];
+
+ } else if ([actionCell type] == NSTextCellType) {
+ [self _localizeTitleOfObject:actionCell table:table];
+ [self _localizeStringValueOfObject:actionCell table:table];
+ }
+ }
+
+ } else if ([object isKindOfClass:[NSMenu class]]) {
+ NSMenu *menu = object;
+ [self _localizeTitleOfObject:menu table:table];
+
+ [self _localizeStringsInObject:[menu itemArray] table:table];
+
+ } else if ([object isKindOfClass:[NSMenuItem class]]) {
+ NSMenuItem *menuItem = object;
+ [self _localizeTitleOfObject:menuItem table:table];
+
+ [self _localizeStringsInObject:[menuItem submenu] table:table];
+
+ } else if ([object isKindOfClass:[NSView class]]) {
+ NSView *view = object;
+ [self _localizeToolTipOfObject:view table:table];
+
+ if ([view isKindOfClass:[NSBox class]]) {
+ NSBox *box = (NSBox *)view;
+ [self _localizeTitleOfObject:box table:table];
+
+ } else if ([view isKindOfClass:[NSControl class]]) {
+ NSControl *control = (NSControl *)view;
+
+ if ([view isKindOfClass:[NSButton class]]) {
+ NSButton *button = (NSButton *)control;
+
+ if ([button isKindOfClass:[NSPopUpButton class]]) {
+ NSPopUpButton *popUpButton = (NSPopUpButton *)button;
+ NSMenu *menu = [popUpButton menu];
+
+ [self _localizeStringsInObject:[menu itemArray] table:table];
+ } else
+ [self _localizeStringsInObject:[button cell] table:table];
+
+
+ } else if ([view isKindOfClass:[NSMatrix class]]) {
+ NSMatrix *matrix = (NSMatrix *)control;
+
+ NSArray *cells = [matrix cells];
+ [self _localizeStringsInObject:cells table:table];
+
+ for (NSCell *cell in cells) {
+
+ NSString *localizedCellToolTip = [self _localizedStringForString:[matrix toolTipForCell:cell] table:table];
+ if (localizedCellToolTip)
+ [matrix setToolTip:localizedCellToolTip forCell:cell];
+ }
+
+ } else if ([view isKindOfClass:[NSSegmentedControl class]]) {
+ NSSegmentedControl *segmentedControl = (NSSegmentedControl *)control;
+
+ NSUInteger segmentIndex, segmentCount = [segmentedControl segmentCount];
+ for (segmentIndex = 0; segmentIndex < segmentCount; segmentIndex++) {
+ NSString *localizedSegmentLabel = [self _localizedStringForString:[segmentedControl labelForSegment:segmentIndex] table:table];
+ if (localizedSegmentLabel)
+ [segmentedControl setLabel:localizedSegmentLabel forSegment:segmentIndex];
+
+ [self _localizeStringsInObject:[segmentedControl menuForSegment:segmentIndex] table:table];
+ }
+
+ } else
+ [self _localizeStringsInObject:[control cell] table:table];
+
+ }
+
+ [self _localizeStringsInObject:[view subviews] table:table];
+
+ } else if ([object isKindOfClass:[NSWindow class]]) {
+ NSWindow *window = object;
+ [self _localizeTitleOfObject:window table:table];
+
+ [self _localizeStringsInObject:[window contentView] table:table];
+
+ }
+}
+
++ (NSString *)_localizedStringForString:(NSString *)string table:(NSString *)table;
+{
+ if (![string length])
+ return nil;
+
+ static NSString *defaultValue = @"I AM THE DEFAULT VALUE";
+ NSString *localizedString = [[NSBundle mainBundle] localizedStringForKey:string value:defaultValue table:table];
+ if (localizedString != defaultValue) {
+ return localizedString;
+ } else {
+#ifdef BETA_BUILD
+ NSLog(@" not going to localize string %@", string);
+ return string; // [string uppercaseString]
+#else
+ return string;
+#endif
+ }
+}
+
+
+#define DM_DEFINE_LOCALIZE_BLAH_OF_OBJECT(blahName, capitalizedBlahName) \
++ (void)_localize ##capitalizedBlahName ##OfObject:(id)object table:(NSString *)table; \
+{ \
+ NSString *localizedBlah = [self _localizedStringForString:[object blahName] table:table]; \
+ if (localizedBlah) \
+ [object set ##capitalizedBlahName:localizedBlah]; \
+}
+
+DM_DEFINE_LOCALIZE_BLAH_OF_OBJECT(title, Title)
+DM_DEFINE_LOCALIZE_BLAH_OF_OBJECT(alternateTitle, AlternateTitle)
+DM_DEFINE_LOCALIZE_BLAH_OF_OBJECT(stringValue, StringValue)
+DM_DEFINE_LOCALIZE_BLAH_OF_OBJECT(placeholderString, PlaceholderString)
+DM_DEFINE_LOCALIZE_BLAH_OF_OBJECT(toolTip, ToolTip)
+
+@end \ No newline at end of file
diff --git a/Source/xibLocalizationPostprocessor.m b/Source/xibLocalizationPostprocessor.m
new file mode 100644
index 00000000..591e92b7
--- /dev/null
+++ b/Source/xibLocalizationPostprocessor.m
@@ -0,0 +1,62 @@
+// xibLocalizationPostprocessor.m
+//
+// Created by William Shipley on 4/14/08.
+// Copyright © 2005-2009 Golden % Braeburn, LLC.
+
+#import <Cocoa/Cocoa.h>
+
+
+int main(int argc, const char *argv[])
+{
+ NSAutoreleasePool *autoreleasePool = [[NSAutoreleasePool alloc] init]; {
+ if (argc != 3) {
+ fprintf(stderr, "Usage: %s inputfile outputfile\n", argv[0]);
+ exit (-1);
+ }
+
+ NSError *error = nil;
+ NSStringEncoding usedEncoding;
+ NSString *rawXIBStrings = [NSString stringWithContentsOfFile:[NSString stringWithUTF8String:argv[1]] usedEncoding:&usedEncoding error:&error];
+ if (error) {
+ fprintf(stderr, "Error reading %s: %s\n", argv[1], error.localizedDescription.UTF8String);
+ exit (-1);
+ }
+
+ NSMutableString *outputStrings = [NSMutableString string];
+ NSUInteger lineCount = 0;
+ NSString *lastComment = nil;
+ for (NSString *line in [rawXIBStrings componentsSeparatedByString:@"\n"]) {
+ lineCount++;
+
+ if ([line hasPrefix:@"/*"]) { // eg: /* Class = "NSMenuItem"; title = "Quit Library"; ObjectID = "136"; */
+ lastComment = line;
+ continue;
+
+ } else if (line.length == 0) {
+ lastComment = nil;
+ continue;
+
+ } else if ([line hasPrefix:@"\""] && [line hasSuffix:@"\";"]) { // eg: "136.title" = "Quit Library";
+
+ NSRange quoteEqualsQuoteRange = [line rangeOfString:@"\" = \""];
+ if (quoteEqualsQuoteRange.length && NSMaxRange(quoteEqualsQuoteRange) < line.length - 1) {
+ if (lastComment) {
+ [outputStrings appendString:lastComment];
+ [outputStrings appendString:@"\n"];
+ }
+ NSString *stringNeedingLocalization = [line substringFromIndex:NSMaxRange(quoteEqualsQuoteRange)]; // chop off leading: "blah" = "
+ stringNeedingLocalization = [stringNeedingLocalization substringToIndex:stringNeedingLocalization.length - 2]; // chop off trailing: ";
+ [outputStrings appendFormat:@"\"%@\" = \"%@\";\n\n", stringNeedingLocalization, stringNeedingLocalization];
+ continue;
+ }
+ }
+
+ NSLog(@"Warning: skipped garbage input line %d, contents: \"%@\"", lineCount, line);
+ }
+
+ if (outputStrings.length && ![outputStrings writeToFile:[NSString stringWithUTF8String:argv[2]] atomically:NO encoding:NSUTF8StringEncoding error:&error]) {
+ fprintf(stderr, "Error writing %s: %s\n", argv[2], error.localizedDescription.UTF8String);
+ exit (-1);
+ }
+ } [autoreleasePool release];
+} \ No newline at end of file