mirror of
https://github.com/tappollo/Xcode-Quick-Localization.git
synced 2026-01-12 22:37:18 +08:00
simple change text
This commit is contained in:
17
.gitignore
vendored
Normal file
17
.gitignore
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
*.mkm
|
||||
# Xcode
|
||||
.DS_Store
|
||||
build/
|
||||
*.pbxuser
|
||||
!default.pbxuser
|
||||
*.mode1v3
|
||||
!default.mode1v3
|
||||
*.mode2v3
|
||||
!default.mode2v3
|
||||
*.perspectivev3
|
||||
!default.perspectivev3
|
||||
!default.xcworkspace
|
||||
xcuserdata
|
||||
*.moved-aside
|
||||
DerivedData
|
||||
.idea/
|
||||
@@ -7,6 +7,7 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
09A343C6174068E600A713EE /* RCXcode.m in Sources */ = {isa = PBXBuildFile; fileRef = 09A343C5174068E200A713EE /* RCXcode.m */; };
|
||||
09F65636174041010000486B /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09F65635174041010000486B /* AppKit.framework */; };
|
||||
09F65638174041010000486B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09F65637174041010000486B /* Foundation.framework */; };
|
||||
09F6563E174041010000486B /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 09F6563C174041010000486B /* InfoPlist.strings */; };
|
||||
@@ -14,6 +15,8 @@
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
09A343C4174068E200A713EE /* RCXcode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCXcode.h; sourceTree = "<group>"; };
|
||||
09A343C5174068E200A713EE /* RCXcode.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RCXcode.m; sourceTree = "<group>"; };
|
||||
09F65632174041010000486B /* QuickLocalization.xcplugin */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = QuickLocalization.xcplugin; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
09F65635174041010000486B /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
|
||||
09F65637174041010000486B /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
|
||||
@@ -68,6 +71,8 @@
|
||||
children = (
|
||||
09F6563F174041010000486B /* QuickLocalization.h */,
|
||||
09F65640174041010000486B /* QuickLocalization.m */,
|
||||
09A343C4174068E200A713EE /* RCXcode.h */,
|
||||
09A343C5174068E200A713EE /* RCXcode.m */,
|
||||
09F6563A174041010000486B /* Supporting Files */,
|
||||
);
|
||||
path = QuickLocalization;
|
||||
@@ -146,6 +151,7 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
09F65641174041010000486B /* QuickLocalization.m in Sources */,
|
||||
09A343C6174068E600A713EE /* RCXcode.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -271,6 +277,7 @@
|
||||
09F65647174041010000486B /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
|
||||
7
QuickLocalization.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
7
QuickLocalization.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:QuickLocalization.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
@@ -7,12 +7,19 @@
|
||||
//
|
||||
|
||||
#import "QuickLocalization.h"
|
||||
|
||||
#import "RCXcode.h"
|
||||
static NSString *localizeRegexs[] = {
|
||||
@"NSLocalizedString\\s*\\(\\s*@\"(.*)\"\\s*,\\s*(.*)\\s*\\)",
|
||||
@"localizedStringForKey:\\s*@\"(.*)\"\\s*value:\\s*(.*)\\s*table:\\s*(.*)",
|
||||
@"NSLocalizedStringFromTable\\s*\\(\\s*@\"(.*)\"\\s*,\\s*(.*)\\s*,\\s*(.*)\\s*\\)",
|
||||
@"NSLocalizedStringFromTableInBundle\\s*\\(\\s*@\"(.*)\"\\s*,\\s*(.*)\\s*,\\s*(.*)\\s*,\\s*(.*)\\s*\\)",
|
||||
@"NSLocalizedStringWithDefaultValue\\s*\\(\\s*@\"(.*)\"\\s*,\\s*(.*)\\s*,\\s*(.*)\\s*,\\s*(.*)\\s*,\\s*(.*)\\s*\\)"
|
||||
};
|
||||
static NSString *stringRegexs = @"@\"[^\"]*\"";
|
||||
@implementation QuickLocalization
|
||||
|
||||
|
||||
+ (void)pluginDidLoad:(NSBundle *)plugin
|
||||
{
|
||||
+ (void)pluginDidLoad:(NSBundle *)plugin {
|
||||
static id sharedPlugin = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
@@ -20,35 +27,87 @@
|
||||
});
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
- (id)init {
|
||||
if (self = [super init]) {
|
||||
// Create menu items, initialize UI, etc.
|
||||
|
||||
// Sample Menu Item:
|
||||
NSMenuItem *viewMenuItem = [[NSApp mainMenu] itemWithTitle:@"File"];
|
||||
if (viewMenuItem) {
|
||||
[[viewMenuItem submenu] addItem:[NSMenuItem separatorItem]];
|
||||
NSMenuItem *sample = [[NSMenuItem alloc] initWithTitle:@"Do Action" action:@selector(doMenuAction) keyEquivalent:@""];
|
||||
[sample setTarget:self];
|
||||
[[viewMenuItem submenu] addItem:sample];
|
||||
[sample release];
|
||||
}
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(applicationDidFinishLaunching:)
|
||||
name:NSApplicationDidFinishLaunchingNotification
|
||||
object:nil];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
// Sample Action, for menu item:
|
||||
- (void)doMenuAction
|
||||
{
|
||||
NSAlert *alert = [NSAlert alertWithMessageText:@"Hello, World" defaultButton:nil alternateButton:nil otherButton:nil informativeTextWithFormat:@""];
|
||||
[alert runModal];
|
||||
- (void)applicationDidFinishLaunching:(NSNotification *)notification {
|
||||
NSMenuItem *viewMenuItem = [[NSApp mainMenu] itemWithTitle:@"Edit"];
|
||||
if (viewMenuItem) {
|
||||
[[viewMenuItem submenu] addItem:[NSMenuItem separatorItem]];
|
||||
NSMenuItem *sample = [[NSMenuItem alloc] initWithTitle:@"Quick Localization" action:@selector(quickLocalization) keyEquivalent:@"c"];
|
||||
[sample setKeyEquivalentModifierMask:NSCommandKeyMask | NSShiftKeyMask];
|
||||
[sample setTarget:self];
|
||||
[[viewMenuItem submenu] addItem:sample];
|
||||
[sample release];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
// Sample Action, for menu item:
|
||||
- (void)quickLocalization {
|
||||
IDESourceCodeDocument *document = [RCXcode currentSourceCodeDocument];
|
||||
NSTextView *textView = [RCXcode currentSourceCodeTextView];
|
||||
if (!document || !textView) {
|
||||
return;
|
||||
}
|
||||
|
||||
// NSLog(@"file: %@", [RCXcode currentWorkspaceDocument].workspace.representingFilePath.fileURL.absoluteString);
|
||||
NSArray *selectedRanges = [textView selectedRanges];
|
||||
if ([selectedRanges count] > 0) {
|
||||
NSRange range = [[selectedRanges objectAtIndex:0] rangeValue];
|
||||
NSRange lineRange = [textView.textStorage.string lineRangeForRange:range];
|
||||
NSString *line = [textView.textStorage.string substringWithRange:lineRange];
|
||||
|
||||
NSRegularExpression *localizedRex = [[[NSRegularExpression alloc] initWithPattern:localizeRegexs[0] options:NSRegularExpressionCaseInsensitive error:nil] autorelease];
|
||||
NSArray *localizedMatches = [localizedRex matchesInString:line options:0 range:NSMakeRange(0, [line length])];
|
||||
|
||||
NSRegularExpression *regex = [[[NSRegularExpression alloc] initWithPattern:stringRegexs options:NSRegularExpressionCaseInsensitive error:nil] autorelease];
|
||||
NSArray *matches = [regex matchesInString:line options:0 range:NSMakeRange(0, [line length])];
|
||||
NSUInteger addedLength = 0;
|
||||
for (int i = 0; i < [matches count]; i++) {
|
||||
NSTextCheckingResult *result = [matches objectAtIndex:i];
|
||||
NSRange matchedRangeInLine = result.range;
|
||||
NSRange matchedRangeInDocument = NSMakeRange(lineRange.location + matchedRangeInLine.location + addedLength, matchedRangeInLine.length);
|
||||
if ([self isRange:matchedRangeInLine inSkipedRanges:localizedMatches]) {
|
||||
continue;
|
||||
}
|
||||
NSString *string = [line substringWithRange:matchedRangeInLine];
|
||||
|
||||
NSString *outputString = [NSString stringWithFormat:@"NSLocalizedString(%@, %@)", string, string];
|
||||
addedLength = outputString.length - string.length;
|
||||
if ([textView shouldChangeTextInRange:matchedRangeInDocument replacementString:outputString]) {
|
||||
[textView.textStorage replaceCharactersInRange:matchedRangeInDocument
|
||||
withAttributedString:[[[NSAttributedString alloc] initWithString:outputString] autorelease]];
|
||||
[textView didChangeText];
|
||||
}
|
||||
|
||||
// [textView replaceCharactersInRange:matchedRangeInDocument withString:outputString];
|
||||
// NSAlert *alert = [NSAlert alertWithMessageText:outputString defaultButton:nil alternateButton:nil otherButton:nil informativeTextWithFormat:@""];
|
||||
// [alert runModal];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)isRange:(NSRange)range inSkipedRanges:(NSArray *)ranges {
|
||||
for (int i = 0; i < [ranges count]; i++) {
|
||||
NSTextCheckingResult *result = [ranges objectAtIndex:i];
|
||||
NSRange skippedRange = result.range;
|
||||
if (skippedRange.location <= range.location && skippedRange.location + skippedRange.length > range.location + range.length) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@end
|
||||
@end
|
||||
122
QuickLocalization/RCXcode.h
Normal file
122
QuickLocalization/RCXcode.h
Normal file
@@ -0,0 +1,122 @@
|
||||
//
|
||||
//
|
||||
// Created by Zitao on 12/05/13.
|
||||
//
|
||||
//
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface DVTTextDocumentLocation : NSObject
|
||||
@property (readonly) NSRange characterRange;
|
||||
@property (readonly) NSRange lineRange;
|
||||
@end
|
||||
|
||||
@interface DVTTextPreferences : NSObject
|
||||
+ (id)preferences;
|
||||
@property BOOL trimWhitespaceOnlyLines;
|
||||
@property BOOL trimTrailingWhitespace;
|
||||
@property BOOL useSyntaxAwareIndenting;
|
||||
@end
|
||||
|
||||
@interface DVTSourceTextStorage : NSTextStorage
|
||||
- (void)replaceCharactersInRange:(NSRange)range withString:(NSString *)string withUndoManager:(id)undoManager;
|
||||
- (NSRange)lineRangeForCharacterRange:(NSRange)range;
|
||||
- (NSRange)characterRangeForLineRange:(NSRange)range;
|
||||
- (void)indentCharacterRange:(NSRange)range undoManager:(id)undoManager;
|
||||
@end
|
||||
|
||||
@interface DVTFileDataType : NSObject
|
||||
@property (readonly) NSString *identifier;
|
||||
@end
|
||||
|
||||
@interface DVTFilePath : NSObject
|
||||
@property (readonly) NSURL *fileURL;
|
||||
@property (readonly) DVTFileDataType *fileDataTypePresumed;
|
||||
@end
|
||||
|
||||
@interface IDEContainerItem : NSObject
|
||||
@property (readonly) DVTFilePath *resolvedFilePath;
|
||||
@end
|
||||
|
||||
@interface IDEGroup : IDEContainerItem
|
||||
|
||||
@end
|
||||
|
||||
@interface IDEFileReference : IDEContainerItem
|
||||
|
||||
@end
|
||||
|
||||
@interface IDENavigableItem : NSObject
|
||||
@property (readonly) IDENavigableItem *parentItem;
|
||||
@property (readonly) id representedObject;
|
||||
@end
|
||||
|
||||
@interface IDEFileNavigableItem : IDENavigableItem
|
||||
@property (readonly) DVTFileDataType *documentType;
|
||||
@property (readonly) NSURL *fileURL;
|
||||
@end
|
||||
|
||||
@interface IDEStructureNavigator : NSObject
|
||||
@property (retain) NSArray *selectedObjects;
|
||||
@end
|
||||
|
||||
@interface IDENavigableItemCoordinator : NSObject
|
||||
- (id)structureNavigableItemForDocumentURL:(id)arg1 inWorkspace:(id)arg2 error:(id *)arg3;
|
||||
@end
|
||||
|
||||
@interface IDENavigatorArea : NSObject
|
||||
- (id)currentNavigator;
|
||||
@end
|
||||
|
||||
@interface IDEWorkspaceTabController : NSObject
|
||||
@property (readonly) IDENavigatorArea *navigatorArea;
|
||||
@end
|
||||
|
||||
@interface IDEDocumentController : NSDocumentController
|
||||
+ (id)editorDocumentForNavigableItem:(id)arg1;
|
||||
+ (id)retainedEditorDocumentForNavigableItem:(id)arg1 error:(id *)arg2;
|
||||
+ (void)releaseEditorDocument:(id)arg1;
|
||||
@end
|
||||
|
||||
@interface IDESourceCodeDocument : NSDocument
|
||||
- (DVTSourceTextStorage *)textStorage;
|
||||
- (NSUndoManager *)undoManager;
|
||||
@end
|
||||
|
||||
@interface IDESourceCodeComparisonEditor : NSObject
|
||||
@property (readonly) NSTextView *keyTextView;
|
||||
@property (retain) NSDocument *primaryDocument;
|
||||
@end
|
||||
|
||||
@interface IDESourceCodeEditor : NSObject
|
||||
@property (retain) NSTextView *textView;
|
||||
- (IDESourceCodeDocument *)sourceCodeDocument;
|
||||
@end
|
||||
|
||||
@interface IDEEditorContext : NSObject
|
||||
- (id)editor; // returns the current editor. If the editor is the code editor, the class is `IDESourceCodeEditor`
|
||||
@end
|
||||
|
||||
@interface IDEEditorArea : NSObject
|
||||
- (IDEEditorContext *)lastActiveEditorContext;
|
||||
@end
|
||||
|
||||
@interface IDEWorkspaceWindowController : NSObject
|
||||
@property (readonly) IDEWorkspaceTabController *activeWorkspaceTabController;
|
||||
- (IDEEditorArea *)editorArea;
|
||||
@end
|
||||
|
||||
@interface IDEWorkspace : NSObject
|
||||
@property (readonly) DVTFilePath *representingFilePath;
|
||||
@end
|
||||
|
||||
@interface IDEWorkspaceDocument : NSDocument
|
||||
@property (readonly) IDEWorkspace *workspace;
|
||||
@end
|
||||
|
||||
@interface RCXcode : NSObject
|
||||
+ (IDEWorkspaceDocument *)currentWorkspaceDocument;
|
||||
+ (IDESourceCodeDocument *)currentSourceCodeDocument;
|
||||
+ (NSTextView *)currentSourceCodeTextView;
|
||||
+ (NSArray *)selectedObjCFileNavigableItems;
|
||||
@end
|
||||
120
QuickLocalization/RCXcode.m
Normal file
120
QuickLocalization/RCXcode.m
Normal file
@@ -0,0 +1,120 @@
|
||||
//
|
||||
//
|
||||
// Created by Zitao on 12/05/13.
|
||||
//
|
||||
//
|
||||
|
||||
#import "RCXcode.h"
|
||||
@implementation RCXcode {}
|
||||
|
||||
#pragma mark - Helpers
|
||||
|
||||
+ (id)currentEditor {
|
||||
NSWindowController *currentWindowController = [[NSApp keyWindow] windowController];
|
||||
if ([currentWindowController isKindOfClass:NSClassFromString(@"IDEWorkspaceWindowController")]) {
|
||||
IDEWorkspaceWindowController *workspaceController = (IDEWorkspaceWindowController *)currentWindowController;
|
||||
IDEEditorArea *editorArea = [workspaceController editorArea];
|
||||
IDEEditorContext *editorContext = [editorArea lastActiveEditorContext];
|
||||
return [editorContext editor];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
+ (IDEWorkspaceDocument *)currentWorkspaceDocument {
|
||||
NSWindowController *currentWindowController = [[NSApp keyWindow] windowController];
|
||||
id document = [currentWindowController document];
|
||||
if (currentWindowController && [document isKindOfClass:NSClassFromString(@"IDEWorkspaceDocument")]) {
|
||||
return (IDEWorkspaceDocument *)document;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
+ (IDESourceCodeDocument *)currentSourceCodeDocument {
|
||||
if ([[RCXcode currentEditor] isKindOfClass:NSClassFromString(@"IDESourceCodeEditor")]) {
|
||||
IDESourceCodeEditor *editor = [RCXcode currentEditor];
|
||||
return editor.sourceCodeDocument;
|
||||
}
|
||||
|
||||
if ([[RCXcode currentEditor] isKindOfClass:NSClassFromString(@"IDESourceCodeComparisonEditor")]) {
|
||||
IDESourceCodeComparisonEditor *editor = [RCXcode currentEditor];
|
||||
if ([[editor primaryDocument] isKindOfClass:NSClassFromString(@"IDESourceCodeDocument")]) {
|
||||
IDESourceCodeDocument *document = (IDESourceCodeDocument *)editor.primaryDocument;
|
||||
return document;
|
||||
}
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
+ (NSTextView *)currentSourceCodeTextView {
|
||||
if ([[RCXcode currentEditor] isKindOfClass:NSClassFromString(@"IDESourceCodeEditor")]) {
|
||||
IDESourceCodeEditor *editor = [RCXcode currentEditor];
|
||||
return editor.textView;
|
||||
}
|
||||
|
||||
if ([[RCXcode currentEditor] isKindOfClass:NSClassFromString(@"IDESourceCodeComparisonEditor")]) {
|
||||
IDESourceCodeComparisonEditor *editor = [RCXcode currentEditor];
|
||||
return editor.keyTextView;
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
+ (NSArray *)selectedObjCFileNavigableItems {
|
||||
NSMutableArray *mutableArray = [NSMutableArray array];
|
||||
|
||||
id currentWindowController = [[NSApp keyWindow] windowController];
|
||||
if ([currentWindowController isKindOfClass:NSClassFromString(@"IDEWorkspaceWindowController")]) {
|
||||
IDEWorkspaceWindowController *workspaceController = currentWindowController;
|
||||
IDEWorkspaceTabController *workspaceTabController = [workspaceController activeWorkspaceTabController];
|
||||
IDENavigatorArea *navigatorArea = [workspaceTabController navigatorArea];
|
||||
id currentNavigator = [navigatorArea currentNavigator];
|
||||
|
||||
if ([currentNavigator isKindOfClass:NSClassFromString(@"IDEStructureNavigator")]) {
|
||||
IDEStructureNavigator *structureNavigator = currentNavigator;
|
||||
for (id selectedObject in structureNavigator.selectedObjects) {
|
||||
if ([selectedObject isKindOfClass:NSClassFromString(@"IDEFileNavigableItem")]) {
|
||||
IDEFileNavigableItem *fileNavigableItem = selectedObject;
|
||||
NSString *uti = fileNavigableItem.documentType.identifier;
|
||||
if ([uti isEqualToString:(NSString *)kUTTypeObjectiveCSource] || [uti isEqualToString:(NSString *)kUTTypeCHeader]) {
|
||||
[mutableArray addObject:fileNavigableItem];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mutableArray.count) {
|
||||
return [NSArray arrayWithArray:mutableArray];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
+ (NSArray *)containerFolderURLsForNavigableItem:(IDENavigableItem *)navigableItem {
|
||||
NSMutableArray *mArray = [NSMutableArray array];
|
||||
|
||||
do {
|
||||
NSURL *folderURL = nil;
|
||||
id representedObject = navigableItem.representedObject;
|
||||
if ([navigableItem isKindOfClass:NSClassFromString(@"IDEGroupNavigableItem")]) {
|
||||
// IDE-GROUP (a folder in the navigator)
|
||||
IDEGroup *group = (IDEGroup *)representedObject;
|
||||
folderURL = group.resolvedFilePath.fileURL;
|
||||
} else if ([navigableItem isKindOfClass:NSClassFromString(@"IDEContainerFileReferenceNavigableItem")]) {
|
||||
// CONTAINER (an Xcode project)
|
||||
IDEFileReference *fileReference = representedObject;
|
||||
folderURL = [fileReference.resolvedFilePath.fileURL URLByDeletingLastPathComponent];
|
||||
} else if ([navigableItem isKindOfClass:NSClassFromString(@"IDEKeyDrivenNavigableItem")]) {
|
||||
// WORKSPACE (root: Xcode project or workspace)
|
||||
IDEWorkspace *workspace = representedObject;
|
||||
folderURL = [workspace.representingFilePath.fileURL URLByDeletingLastPathComponent];
|
||||
}
|
||||
if (folderURL && ![mArray containsObject:folderURL]) [mArray addObject:folderURL];
|
||||
navigableItem = [navigableItem parentItem];
|
||||
} while (navigableItem != nil);
|
||||
|
||||
if (mArray.count > 0) return [NSArray arrayWithArray:mArray];
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in New Issue
Block a user