Plugin display is now more verbose

The plugin settings now displays more information about a failed plugin instead of just not displaying anything at all.
This commit is contained in:
michael starke
2017-11-20 12:51:39 +01:00
parent ec62a3e12c
commit c33c6a8cfa
11 changed files with 194 additions and 48 deletions

View File

@@ -644,6 +644,7 @@
4C8B36A917A6ED4B005E1FF1 /* MPOutlineContextMenuDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPOutlineContextMenuDelegate.h; sourceTree = "<group>"; };
4C8B36AA17A6ED4B005E1FF1 /* MPOutlineContextMenuDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPOutlineContextMenuDelegate.m; sourceTree = "<group>"; };
4C8DEAA11C314D2C00D24C32 /* MPTestAutotypeDelay.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPTestAutotypeDelay.m; sourceTree = "<group>"; };
4C8FB9FA1FC2D0EF003691AA /* MPPlugin_Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPPlugin_Private.h; sourceTree = "<group>"; };
4C93C5701FBDFEF700F36855 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/AutotypeCandidateSelectionView.strings; sourceTree = "<group>"; };
4C93C5711FBDFEF900F36855 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/AutotypeBuilderView.strings; sourceTree = "<group>"; };
4C978E0C19AE54AB003067DF /* MPFlagsHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPFlagsHelper.m; sourceTree = "<group>"; };
@@ -1541,6 +1542,7 @@
isa = PBXGroup;
children = (
4CD034A41BFE113B003C002C /* MPPlugin.h */,
4C8FB9FA1FC2D0EF003691AA /* MPPlugin_Private.h */,
4CD034A51BFE113B003C002C /* MPPlugin.m */,
4CD034A81BFE113B003C002C /* MPPluginHost.h */,
4CD034A91BFE113B003C002C /* MPPluginHost.m */,

View File

@@ -10,6 +10,8 @@
<customObject id="-2" userLabel="File's Owner" customClass="MPPluginSettingsController">
<connections>
<outlet property="addRemovePluginsControl" destination="B9Q-hq-K4N" id="Oqj-Ko-8UR"/>
<outlet property="fallbackDescriptionTextField" destination="qPL-FR-ky7" id="xCb-ED-NIX"/>
<outlet property="fallbackSettingsView" destination="wIk-iw-Tcz" id="dHl-zW-0aI"/>
<outlet property="loadInsecurePlugsinCheckButton" destination="CqP-oK-S8k" id="YET-o6-7Cc"/>
<outlet property="pluginTableView" destination="Ocu-C0-03d" id="jbH-qr-bVT"/>
<outlet property="settingsView" destination="tD5-Na-7XI" id="Pa0-Tt-20U"/>
@@ -26,6 +28,33 @@
<view key="contentView" id="tD5-Na-7XI">
<rect key="frame" x="1" y="1" width="326" height="349"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<customView translatesAutoresizingMaskIntoConstraints="NO" id="wIk-iw-Tcz">
<rect key="frame" x="20" y="20" width="286" height="309"/>
<subviews>
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="qPL-FR-ky7">
<rect key="frame" x="18" y="272" width="122" height="17"/>
<textFieldCell key="cell" controlSize="mini" sendsActionOnEndEditing="YES" title="Plugin Settings Info" id="OOr-SW-jZb">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<constraints>
<constraint firstItem="qPL-FR-ky7" firstAttribute="top" secondItem="wIk-iw-Tcz" secondAttribute="top" constant="20" symbolic="YES" id="BAH-sF-W03"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="qPL-FR-ky7" secondAttribute="trailing" constant="20" symbolic="YES" id="HKa-7h-OiN"/>
<constraint firstItem="qPL-FR-ky7" firstAttribute="leading" secondItem="wIk-iw-Tcz" secondAttribute="leading" constant="20" symbolic="YES" id="UTY-Lu-pvl"/>
<constraint firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="qPL-FR-ky7" secondAttribute="bottom" constant="20" symbolic="YES" id="wpb-76-pxa"/>
</constraints>
</customView>
</subviews>
<constraints>
<constraint firstItem="wIk-iw-Tcz" firstAttribute="top" secondItem="tD5-Na-7XI" secondAttribute="top" constant="20" symbolic="YES" id="JEm-yQ-dbO"/>
<constraint firstAttribute="trailing" secondItem="wIk-iw-Tcz" secondAttribute="trailing" constant="20" symbolic="YES" id="Zfc-6L-EPa"/>
<constraint firstAttribute="bottom" secondItem="wIk-iw-Tcz" secondAttribute="bottom" constant="20" symbolic="YES" id="mGC-Qx-83s"/>
<constraint firstItem="wIk-iw-Tcz" firstAttribute="leading" secondItem="tD5-Na-7XI" secondAttribute="leading" constant="20" symbolic="YES" id="phc-Nv-2hD"/>
</constraints>
</view>
</box>
<button translatesAutoresizingMaskIntoConstraints="NO" id="CqP-oK-S8k">
@@ -115,8 +144,8 @@
<constraint firstAttribute="width" constant="150" id="ZpW-Bc-fSx"/>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="150" id="eXb-yq-O8y"/>
</constraints>
<scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="YES" id="UK5-gt-5o5">
<rect key="frame" x="1" y="133" width="148" height="16"/>
<scroller key="horizontalScroller" verticalHuggingPriority="750" horizontal="YES" id="UK5-gt-5o5">
<rect key="frame" x="1" y="328" width="148" height="16"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<scroller key="verticalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="NO" id="oqL-7I-4H1">
@@ -169,7 +198,7 @@
<constraint firstItem="vBs-Ga-aq0" firstAttribute="leading" secondItem="fCk-fL-jU8" secondAttribute="trailing" constant="8" id="xNu-Sj-xQO"/>
<constraint firstItem="aoG-FD-ds8" firstAttribute="top" secondItem="CqP-oK-S8k" secondAttribute="bottom" constant="8" symbolic="YES" id="zSW-h3-BrT"/>
</constraints>
<point key="canvasLocation" x="96" y="-112"/>
<point key="canvasLocation" x="-344" y="-85"/>
</customView>
</objects>
<resources>

View File

@@ -33,6 +33,7 @@ FOUNDATION_EXPORT NSString *const kMPPluginFileExtension;
@property (copy, readonly) NSString *identifier;
@property (copy, readonly) NSString *name;
@property (copy, readonly) NSString *version;
@property (nonatomic, strong, readonly) NSBundle *bundle;
- (instancetype)initWithPluginHost:(MPPluginHost *)host NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;

View File

@@ -21,6 +21,7 @@
//
#import "MPPlugin.h"
#import "MPPlugin_Private.h"
#import "MPPluginHost.h"
#import "MPSettingsHelper.h"
@@ -28,15 +29,35 @@ NSString *const kMPPluginFileExtension = @"mpplugin";
@implementation MPPlugin
@synthesize bundle = _bundle;
- (instancetype)initWithPluginHost:(MPPluginHost *)host {
self = [super init];
if(self) {
_enabled = YES;
}
return self;
}
- (NSBundle *)bundle {
if(_enabled) {
return [NSBundle bundleForClass:self.class];
}
else {
return _bundle;
}
}
- (void)setBundle:(NSBundle *)bundle {
self.enabled = NO;
if(_bundle != bundle) {
_bundle = bundle;
}
}
- (NSString *)identifier {
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
if(bundle && bundle.bundleIdentifier) {
return bundle.bundleIdentifier;
if(self.bundle.bundleIdentifier) {
return self.bundle.bundleIdentifier;
}
return [NSString stringWithFormat:@"unknown.bundle.identifier"];
}
@@ -47,10 +68,9 @@ NSString *const kMPPluginFileExtension = @"mpplugin";
}
- (NSString *)version {
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
if(bundle) {
NSString *humanVersion = bundle.infoDictionary[@"CFBundleShortVersionString"];
NSString *version = bundle.infoDictionary[(NSString *)kCFBundleVersionKey];
if(self.bundle) {
NSString *humanVersion = self.bundle.infoDictionary[@"CFBundleShortVersionString"];
NSString *version = self.bundle.infoDictionary[(NSString *)kCFBundleVersionKey];
if(humanVersion && version) {
return [NSString stringWithFormat:@"%@ (%@)", humanVersion, version];
}

View File

@@ -31,6 +31,7 @@ FOUNDATION_EXPORT NSString *const MPPluginHostPluginBundleIdentifiyerKey;
@interface MPPluginHost : NSObject
/* List of all plugins known to the plugin manager. Disabled plugins are also present! */
@property (readonly, copy) NSArray <MPPlugin __kindof*> *plugins;
@property (nonatomic, readonly) BOOL loadUnsecurePlugins;

View File

@@ -23,6 +23,7 @@
#import "MPPluginHost.h"
#import "MPPlugin.h"
#import "MPPlugin_Private.h"
#import "NSApplication+MPAdditions.h"
#import "MPSettingsHelper.h"
@@ -88,7 +89,7 @@ NSString *const MPPluginHostPluginBundleIdentifiyerKey = @"MPPluginHostPluginBun
}
- (BOOL)installPluginAtURL:(NSURL *)url error:(NSError *__autoreleasing *)error {
if(![self _validURL:url]) {
if(![self _isValidPluginURL:url]) {
if(error) {
*error = [NSError errorWithCode:MPErrorInvalidPlugin description:NSLocalizedString(@"ERROR_INVALID_PLUGIN", @"Error description given when adding an invalid plugin")];
}
@@ -104,8 +105,7 @@ NSString *const MPPluginHostPluginBundleIdentifiyerKey = @"MPPluginHostPluginBun
}
- (BOOL)uninstallPlugin:(MPPlugin *)plugin error:(NSError *__autoreleasing *)error {
NSBundle *pluginBundle = [NSBundle bundleForClass:plugin.class];
return [NSFileManager.defaultManager trashItemAtURL:pluginBundle.bundleURL resultingItemURL:nil error:error];
return [NSFileManager.defaultManager trashItemAtURL:plugin.bundle.bundleURL resultingItemURL:nil error:error];
}
- (void)disablePlugin:(MPPlugin *)plugin {
@@ -120,17 +120,18 @@ NSString *const MPPluginHostPluginBundleIdentifiyerKey = @"MPPluginHostPluginBun
- (void)_loadPlugins {
NSURL *appSupportDir = [NSApp applicationSupportDirectoryURL:YES];
NSError *error;
NSLog(@"Looking for external plugins at %@.", appSupportDir.path);
NSArray *externalPluginsURLs = [[NSFileManager defaultManager] contentsOfDirectoryAtURL:appSupportDir
includingPropertiesForKeys:@[]
options:NSDirectoryEnumerationSkipsHiddenFiles
error:&error];
NSLog(@"Looking for internal plugins");
NSArray *internalPluginsURLs = [[NSFileManager defaultManager] contentsOfDirectoryAtURL:[NSBundle mainBundle].builtInPlugInsURL
includingPropertiesForKeys:@[]
options:NSDirectoryEnumerationSkipsHiddenFiles
error:&error];
if(!externalPluginsURLs) {
// No external plugins
NSLog(@"No external plugins found!");
@@ -142,29 +143,31 @@ NSString *const MPPluginHostPluginBundleIdentifiyerKey = @"MPPluginHostPluginBun
NSArray *pluginURLs = [externalPluginsURLs arrayByAddingObjectsFromArray:internalPluginsURLs];
for(NSURL *pluginURL in pluginURLs) {
if(![self _validURL:pluginURL]) {
if(![self _isValidPluginURL:pluginURL]) {
NSLog(@"Skipping %@. No valid plugin file.", pluginURL.path);
continue;
}
if(![self _validSignature:pluginURL]) {
continue;
}
NSBundle *pluginBundle = [NSBundle bundleWithURL:pluginURL];
if(!pluginBundle) {
NSLog(@"Could not create bundle %@", pluginURL.path);
NSLog(@"Could not access plugin bundle %@", pluginURL.path);
continue;
}
if(pluginBundle.bundleIdentifier) {
if(![self _isSignedPluginURL:pluginURL]) {
if(self.loadUnsecurePlugins) {
NSLog(@"Loading unsecure Plugin at %@.", pluginURL.path);
}
else {
[self _addPluginForBundle:pluginBundle error:NSLocalizedString(@"PLUGIN_ERROR_UNSECURE_PLUGIN", "Error for a plugin that was not signed properly")];
continue;
}
}
NSError *error;
if(![pluginBundle preflightAndReturnError:&error]) {
NSLog(@"Preflight Error %@ %@", error.localizedDescription, error.localizedFailureReason );
[self _addPluginForBundle:pluginBundle error:error.localizedDescription];
continue;
};
@@ -175,11 +178,13 @@ NSString *const MPPluginHostPluginBundleIdentifiyerKey = @"MPPluginHostPluginBun
if(![pluginBundle loadAndReturnError:&error]) {
NSLog(@"Bundle Loading Error %@ %@", error.localizedDescription, error.localizedFailureReason);
[self _addPluginForBundle:pluginBundle error:error.localizedDescription];
continue;
}
if(![self _validateClass:pluginBundle.principalClass]) {
if(![self _isValidPluginClass:pluginBundle.principalClass]) {
NSLog(@"Wrong principal Class.");
[self _addPluginForBundle:pluginBundle error:NSLocalizedString(@"PLUGIN_ERROR_WRONG_PRINCIPAL_CLASS", "Plugin specifies the wrong principla class!".)];
continue;
}
@@ -207,10 +212,19 @@ NSString *const MPPluginHostPluginBundleIdentifiyerKey = @"MPPluginHostPluginBun
}
else {
NSLog(@"Unable to create instance of plugin class %@", pluginBundle.principalClass);
[self _addPluginForBundle:pluginBundle error:NSLocalizedString(@"PLUGIN_ERROR_INTILIZATION_FAILED", "The plugin could not be initalized".)];
}
}
}
- (void)_addPluginForBundle:(NSBundle *)bundle error:(NSString *)errorMessage {
MPPlugin *plugin = [[MPPlugin alloc] initWithPluginHost:self];
plugin.bundle = bundle;
plugin.enabled = NO;
plugin.errorMessage = errorMessage;
[self.mutablePlugins addObject:plugin];
}
- (BOOL)_validateUniqueBundle:(NSBundle *)bundle {
for(MPPlugin *plugin in self.mutablePlugins) {
NSBundle *pluginBundle = [NSBundle bundleForClass:plugin.class];
@@ -221,24 +235,20 @@ NSString *const MPPluginHostPluginBundleIdentifiyerKey = @"MPPluginHostPluginBun
return NO;
}
- (BOOL)_validURL:(NSURL *)url {
- (BOOL)_isValidPluginURL:(NSURL *)url {
return (NSOrderedSame == [url.pathExtension compare:kMPPluginFileExtension options:NSCaseInsensitiveSearch]);
}
- (BOOL)_validateClass:(Class)class {
- (BOOL)_isValidPluginClass:(Class)class {
return [class isSubclassOfClass:[MPPlugin class]];
}
/* Code by Jedda Wignall<jedda@jedda.me> http://jedda.me/2012/03/verifying-plugin-bundles-using-code-signing/ */
- (BOOL)_validSignature:(NSURL *)url {
- (BOOL)_isSignedPluginURL:(NSURL *)url {
if(!url.path) {
return NO;
}
if(self.loadUnsecurePlugins) {
return YES;
}
NSTask * task = [[NSTask alloc] init];
NSPipe * pipe = [NSPipe pipe];
NSArray* args = @[ @"--verify",
@@ -258,16 +268,16 @@ NSString *const MPPluginHostPluginBundleIdentifiyerKey = @"MPPluginHostPluginBun
NSString * taskString = [[NSString alloc] initWithData:pipe.fileHandleForReading.readDataToEndOfFile encoding:NSASCIIStringEncoding];
if ([taskString rangeOfString:@"modified"].length > 0 || [taskString rangeOfString:@"a sealed resource is missing or invalid"].length > 0) {
// The plugin has been modified or resources removed since being signed. You probably don't want to load this.
NSLog(@"Plugin %@ modified - not loaded", pluginPath); // log a real error here
NSLog(@"Plugin %@ modified", pluginPath); // log a real error here
}
else if ([taskString rangeOfString:@"failed to satisfy"].length > 0) {
// The plugin is missing resources since being signed. Don't load.
// throw an error
NSLog(@"Plugin %@ not signed by correct CA - not loaded", pluginPath); // log a real error here
NSLog(@"Plugin %@ not signed by correct CA", pluginPath); // log a real error here
}
else if ([taskString rangeOfString:@"not signed at all"].length > 0) {
// The plugin was not code signed at all. Don't load.
NSLog(@"Plugin %@ not signed at all - don't load.", pluginPath); // log a real error here
NSLog(@"Plugin %@ not signed at all.", pluginPath); // log a real error here
}
else {
NSLog(@"Unkown CodeSign Error!");

View File

@@ -24,6 +24,7 @@
#import "MPPluginTabelCellView.h"
#import "MPPluginHost.h"
#import "MPPlugin.h"
#import "MPPlugin_Private.h"
#import "MPConstants.h"
#import "MPSettingsHelper.h"
@@ -41,6 +42,8 @@ typedef NS_ENUM(NSUInteger, MPPluginSegmentType) {
@property (weak) IBOutlet NSTableView *pluginTableView;
@property (weak) IBOutlet NSView *settingsView;
@property (strong) IBOutlet NSView *fallbackSettingsView;
@property (weak) IBOutlet NSTextField *fallbackDescriptionTextField;
@property (weak) IBOutlet NSButton *loadInsecurePlugsinCheckButton;
@property (weak) IBOutlet NSSegmentedControl *addRemovePluginsControl;
@@ -68,7 +71,7 @@ typedef NS_ENUM(NSUInteger, MPPluginSegmentType) {
self.pluginTableView.delegate = self;
self.pluginTableView.dataSource = self;
[self.addRemovePluginsControl setEnabled:NO forSegment:MPRemovePluginSegment];
[self.fallbackSettingsView removeFromSuperview];
[self.loadInsecurePlugsinCheckButton bind:NSValueBinding
toObject:[NSUserDefaultsController sharedUserDefaultsController]
withKeyPath:[MPSettingsHelper defaultControllerPathForKey:kMPSettingsKeyLoadUnsecurePlugins]
@@ -77,7 +80,6 @@ typedef NS_ENUM(NSUInteger, MPPluginSegmentType) {
}
# pragma mark - TableView
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView {
return [MPPluginHost sharedHost].plugins.count;
}
@@ -85,7 +87,14 @@ typedef NS_ENUM(NSUInteger, MPPluginSegmentType) {
- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
MPPlugin *plugin = [self pluginForRow:row];
MPPluginTabelCellView *view = [tableView makeViewWithIdentifier:tableColumn.identifier owner:nil];
view.textField.stringValue = [NSString stringWithFormat:@"%@", plugin.name];
if(plugin.enabled) {
view.textField.stringValue = plugin.name;
}
else {
view.textField.stringValue = (plugin.errorMessage.length > 0
? [NSString stringWithFormat:NSLocalizedString(@"PLUGIN_NAME_ERROR_%@", "Name for unloaded plugin with errors"), plugin.name]
: [NSString stringWithFormat:NSLocalizedString(@"PLUGIN_NAME_DISABLED_%@", "name for disabled unloaded plugin"), plugin.name]);
}
view.addionalTextField.stringValue = [NSString stringWithFormat:NSLocalizedString(@"PLUGIN_VERSION_%@", "Plugin version. Include a %@ placeholder for version string"), plugin.version];
return view;
}
@@ -93,14 +102,29 @@ typedef NS_ENUM(NSUInteger, MPPluginSegmentType) {
- (void)showSettingsForPlugin:(MPPlugin *)plugin {
/* move old one regardless */
[self.settingsView.subviews.firstObject removeFromSuperview];
if([plugin conformsToProtocol:@protocol(MPPluginSettings)]) {
NSAssert([plugin respondsToSelector:@selector(settingsViewController)], @"Required getter for settings on plugins");
NSViewController *viewController = ((id<MPPluginSettings>)plugin).settingsViewController;
[self.settingsView addSubview:viewController.view];
NSDictionary *dict = @{ @"view" : viewController.view,
if(plugin.enabled) {
if([plugin conformsToProtocol:@protocol(MPPluginSettings)]) {
NSAssert([plugin respondsToSelector:@selector(settingsViewController)], @"Required getter for settings on plugins");
NSViewController *viewController = ((id<MPPluginSettings>)plugin).settingsViewController;
[self.settingsView addSubview:viewController.view];
NSDictionary *dict = @{ @"view" : viewController.view,
@"table" : self.pluginTableView.enclosingScrollView };
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[view]|" options:0 metrics:nil views:dict]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[view]|" options:0 metrics:nil views:dict]];
}
}
else if(nil != plugin) {
[self.settingsView addSubview:self.fallbackSettingsView];
NSDictionary *dict = @{ @"view" : self.fallbackSettingsView,
@"table" : self.pluginTableView.enclosingScrollView };
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[view]|" options:0 metrics:nil views:dict]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[view]|" options:0 metrics:nil views:dict]];
if(plugin.errorMessage.length > 0) {
self.fallbackDescriptionTextField.stringValue = plugin.errorMessage;
}
else {
self.fallbackDescriptionTextField.stringValue = NSLocalizedString(@"PLUGIN_SETTINGS_GENERIC_ERROR_MESSAGE", "Generic message displayed if no details are know why a plugin was not loaded.");
}
}
}
@@ -188,7 +212,7 @@ typedef NS_ENUM(NSUInteger, MPPluginSegmentType) {
if(NSModalResponseOK) {
if(openPanel.URLs.count == 1) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self _addPlugin:openPanel.URLs.firstObject];
[self _addPlugin:openPanel.URLs.firstObject];
});
}
}

View File

@@ -0,0 +1,17 @@
//
// MPPlugin+Private.h
// MacPass
//
// Created by Michael Starke on 20.11.17.
// Copyright © 2017 HicknHack Software GmbH. All rights reserved.
//
#import "MPPlugin.h"
@interface MPPlugin ()
@property (nonatomic, strong) NSBundle *bundle;
@property (copy) NSString *errorMessage;
@property BOOL enabled;
@end

View File

@@ -416,9 +416,27 @@
/* Menu item to perform autotype with the selected entry */
"PERFORM_AUTOTYPE_FOR_ENTRY" = "Auto-Type ausführen";
/* The plugin could not be initalized */
"PLUGIN_ERROR_INTILIZATION_FAILED" = "Das Plugin konnten nicht korrekt initialisiert werden";
/* Error for a plugin that was not signed properly */
"PLUGIN_ERROR_UNSECURE_PLUGIN" = "Das Plugin ist nicht korrekt signiert";
/* Plugin specifies the wrong principla class! */
"PLUGIN_ERROR_WRONG_PRINCIPAL_CLASS" = "Die Hauptklasse des Plugins stimmt nicht mit der erwarteten überein";
/* name for disabled unloaded plugin */
"PLUGIN_NAME_DISABLED_%@" = "🚫 %@";
/* Name for unloaded plugin with errors */
"PLUGIN_NAME_ERROR_%@" = "⚠️ %@";
/* Label for plugin settings tab */
"PLUGIN_SETTINGS" = "Plugins";
/* Generic message displayed if no details are know why a plugin was not loaded. */
"PLUGIN_SETTINGS_GENERIC_ERROR_MESSAGE" = "Das Plugin konnte nicht geladen werden.";
/* Plugin version. Include a %@ placeholder for version string */
"PLUGIN_VERSION_%@" = "Version: %@";

View File

@@ -34,12 +34,12 @@
/* Alert informative text to ask the user if he really want to uninstall the plugin */
"ALERT_INFORMATIVE_TEXT_REALLY_UNINSTALL_PLUGIN" = "The Plugin will be moved to the Trash.";
/* Alert message text when a plugin was successfully installed */
"ALERT_MESSAGE_TEXT_PLUGIN_INSTALLED_SUGGEST_RESTART" = "Sucessfully installed Plugin!";
/* Alert message text when a plugin was successfully uninstalled. Include %@ placeholder for plugin name */
"ALERT_MESSAGE_TEXT_PLUGIN_%@_UNINSTALLED_SUGGEST_RESTART" = "Plugin %@ uninstalled!";
/* Alert message text when a plugin was successfully installed */
"ALERT_MESSAGE_TEXT_PLUGIN_INSTALLED_SUGGEST_RESTART" = "Sucessfully installed Plugin!";
/* Alert message text to ask the user if he really want to uninstall the plugin. Include %@ placeholder for plugin name */
"ALERT_MESSAGE_TEXT_REALLY_UNINSTALL_PLUGIN_%@" = "Should the Plugin %@ really be uninstalled?";
@@ -416,9 +416,27 @@
/* Menu item to perform autotype with the selected entry */
"PERFORM_AUTOTYPE_FOR_ENTRY" = "Perform Autotype";
/* The plugin could not be initalized */
"PLUGIN_ERROR_INTILIZATION_FAILED" = "Plugin could not be initalized";
/* Error for a plugin that was not signed properly */
"PLUGIN_ERROR_UNSECURE_PLUGIN" = "Plugin is not properly signed";
/* Plugin specifies the wrong principla class! */
"PLUGIN_ERROR_WRONG_PRINCIPAL_CLASS" = "Plugin principal class is wrong";
/* name for disabled unloaded plugin */
"PLUGIN_NAME_DISABLED_%@" = "🚫 %@";
/* Name for unloaded plugin with errors */
"PLUGIN_NAME_ERROR_%@" = "⚠️ %@";
/* Label for plugin settings tab */
"PLUGIN_SETTINGS" = "Plugins";
/* Generic message displayed if no details are know why a plugin was not loaded. */
"PLUGIN_SETTINGS_GENERIC_ERROR_MESSAGE" = "Plugin could not be loaded.";
/* Plugin version. Include a %@ placeholder for version string */
"PLUGIN_VERSION_%@" = "Version: %@";

View File

@@ -4,6 +4,9 @@
/* Class = "NSButtonCell"; title = "Load unsecure Plugins"; ObjectID = "C4B-6z-ZqX"; */
"C4B-6z-ZqX.title" = "Load unsecure Plugins";
/* Class = "NSTextFieldCell"; title = "Plugin Settings Info"; ObjectID = "OOr-SW-jZb"; */
"OOr-SW-jZb.title" = "Plugin Settings Info";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "STt-PQ-Szr"; */
"STt-PQ-Szr.title" = "Text Cell";
@@ -16,3 +19,6 @@
/* Class = "NSBox"; title = "Box"; ObjectID = "vBs-Ga-aq0"; */
"vBs-Ga-aq0.title" = "Box";
/* Class = "NSTextFieldCell"; title = "Label"; ObjectID = "yuK-qH-jxx"; */
"yuK-qH-jxx.title" = "Label";