Relator

    In the course of my work, I come across small tasks that take a lot of time (when solving “head-on”). Sometimes it turns out to find means to quickly solve these problems, sometimes not. In the second case, most often, I quickly write my own small programs that allow you to simplify the solution to the problem as much as possible.

    Recently faced with one such task. Increasingly, the need arose to translate some text. It was necessary to translate a paragraph in Hebrew, or a discussion to be read on a Chinese site, or when writing a letter to foreign colleagues, it was not possible to translate a “tricky” sentence — you had to turn to online translation services (“take a peek” at the prompt). I used the services of PROMT and Google. This approach began to bother me, and for a couple of evenings I drew up a contextual translator that uses three services from companies at once: Google (Google Translator), Microsoft (Bing Translator), PROMT (mobile version).

    image

    I am sure that my experience will be useful to someone.

    I will divide this mini-article into two parts. The first is dedicated to those who just want to install the program and use it. And the second one, that only takes the first steps in mastering the development of “for” Mac OS X and iPhone (they made the first “Converter” program for Apple's leadership, but already having the desire to write commercial software).


    Relator is a simple but convenient contextual translator for Mac OS X. There may be bugs, crashes - I haven’t tested it in detail (there was no need), but it has been working fine for me for several days.

    Apple at Mac OS X 10.6 (Snow Leopard) finally drew attention to the functionality of Services (Services) and very “combed” it. Relator is based on this functionality.

    INSTALLATION

    1). Copy Translation.service into the Services folder:

    [HOME FOLDER] / Libraries / Services - if the service is needed only by you.
    / Libraries / Services - if the service is needed by all users in the system.

    If the Services folder is not in the right place, then just create it.

    image

    2). Double-click on the service (start) or log out and log in.

    3). Open System Preferences> Keyboard> Services. We put a tick in front of “Translate” and set a convenient keyboard shortcut.

    image

    4). All. The context translator is completely ready for work.

    USING

    In any program that supports Services (Safari, Mail, Skype, iChat, TextEdit, Pages, etc.), select the text, right-click to open the context menu and select “Translate” - a window will open under the cursor with by transfer. Or highlight the text and press the specified keyboard shortcut.

    image
    image

    Important notice ... Some programs (especially cross-platform) do not support the functionality of the Service.

    Relator for each translation uses its own window. Those. the previous window with the previous translation does not close when translating new text.

    You can configure the translator window size convenient for you. Simply adjust the window to the required size, and all of the following windows will be the same size.

    The translation service provider is automatically saved. For example, if you selected Microsoft in the last window, then the next translation will automatically display the translation from Microsoft.

    image

    In the program settings you can set the font size of the translation and a couple of languages ​​for the default translation.

    image

    If the language is not supported by the provider, we will see the corresponding message.

    You can download the program from the link: http://www.yuriev.info/translator/translator.zip
    System requirements: Mac OS X 10.6 and higher

    LIMITATIONS

    The program does not allow translating very long texts (in the technical sense, the request length should not exceed 2000 characters ) The program uses GET methods, not POST.

    The program uses the mobile version of PROMT (m.translate.ru), which can only be translated in small paragraphs.

    FOR THE BEGINNING DEVELOPERS

    I have collected here a number of banal and not very questions (which are relevant for Relator) and gave answers to them.

    How to create a HUD interface?

    Apple for developers is only a HUD panel. The user must create all elements independently or use ready-made libraries. I used BGHUDAppKit.

    How to save and load certain program settings?

    Use the NSUserDefaults class.

      NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];  
      NSString *source = [defaults objectForKey:@"SourceLanguage"];
    ...
      [defaults setObject:language forKey:@"SourceLanguage"];

    * This source code was highlighted with Source Code Highlighter.


    How to set the contents of NSPopUpButton?

    For example, like this:

      [sourceLanguagesButton removeAllItems];
      
      [sourceLanguagesButton addItemWithTitle:NSLocalizedString(@"auto", @"")];
      [[sourceLanguagesButton menu] addItem:[NSMenuItem separatorItem]];
      
      for (int i = 0; i < 10; i++)
      {
        [sourceLanguagesButton addItemWithTitle:[NSString stringWithFormat:@"%i", i]];
      }

    * This source code was highlighted with Source Code Highlighter.


    How to set the color of the text on the button?

      [contactButton setTitle:NSLocalizedString(@"Contact", @"")];
      NSMutableAttributedString *colorTitle = [[NSMutableAttributedString alloc] initWithAttributedString:[contactButton attributedTitle]];  
      [colorTitle addAttribute:NSForegroundColorAttributeName value:[NSColor whiteColor] range:NSMakeRange(0, [colorTitle length])];
      [contactButton setAttributedTitle:colorTitle];
      [colorTitle addAttribute:NSForegroundColorAttributeName value:[NSColor blackColor] range:NSMakeRange(0, [colorTitle length])];  
      [contactButton setAttributedAlternateTitle:colorTitle];
      [colorTitle release];

    * This source code was highlighted with Source Code Highlighter.


    How to apply CoreImage effects to a window (for example, make a blur like Windows)?

    A private API is indispensable.

    Declare:

    typedef void *CGSWindowFilterRef;
    typedef int    CGSConnectionID;
    typedef int    CGSWindowID;
    extern CGSConnectionID _CGSDefaultConnection(void);
    extern CGError CGSNewCIFilterByName(CGSConnectionID cid, CFStringRef filterName, CGSWindowFilterRef *outFilter);
    extern CGError CGSAddWindowFilter(CGSConnectionID cid, CGSWindowID wid, CGSWindowFilterRef filter, int flags);
    extern CGError CGSRemoveWindowFilter(CGSConnectionID cid, CGSWindowID wid, CGSWindowFilterRef filter);
    extern CGError CGSReleaseCIFilter(CGSConnectionID cid, CGSWindowFilterRef filter);
    extern CGError CGSSetCIFilterValuesFromDictionary(CGSConnectionID cid, CGSWindowFilterRef filter, CFDictionaryRef filterValues);

    * This source code was highlighted with Source Code Highlighter.


    We set the filter:

      CGSWindowID wid;
      CGSWindowFilterRef fid;  

    * This source code was highlighted with Source Code Highlighter.


    ...

      int compositingType = 1;
      wid = [[self window] windowNumber];
      CGSNewCIFilterByName(_CGSDefaultConnection(), (CFStringRef)@"CIGaussianBlur", &fid);
      NSDictionary *options = [NSDictionary dictionaryWithObject:[NSNumber numberWithFloat:3.0] forKey:@"inputRadius"];
      CGSSetCIFilterValuesFromDictionary(_CGSDefaultConnection(), fid, (CFDictionaryRef)options);  
      CGSAddWindowFilter(_CGSDefaultConnection(), wid, fid, compositingType);

    * This source code was highlighted with Source Code Highlighter.


    We remove the filter:

      if (fid)
      {
        CGSRemoveWindowFilter(_CGSDefaultConnection(), wid, fid);
        CGSReleaseCIFilter(_CGSDefaultConnection(), fid);
      }

    * This source code was highlighted with Source Code Highlighter.


    How to access the NSView window title object (to place any additional elements there, for example, a lock, as in Safari)?

      NSView *titlebar = [[self.window standardWindowButton:NSWindowCloseButton] superview];

    * This source code was highlighted with Source Code Highlighter.


    How to get the current coordinates of the mouse cursor?

      NSPoint point = [NSEvent mouseLocation];

    * This source code was highlighted with Source Code Highlighter.


    How to change the font of the entire contents of an NSTextView object?

      [textView setFont:[NSFont systemFontOfSize:20]];

    * This source code was highlighted with Source Code Highlighter.


    How to programmatically set the starting position in NSTextView (scrolling to the very beginning)?

      NSPoint top;
      
      if([textView isFlipped])
      {
        top = NSMakePoint(0.0, 0.0);
      }
      else
      {
        top = NSMakePoint(0.0, NSMaxY([textView frame]) - NSHeight([textView bounds]));
      }
      
      [textView scrollPoint:top];  

    * This source code was highlighted with Source Code Highlighter.


    How to hide some object of the NSView class (for example, a button)?

      [object setHidden:YES];    

    * This source code was highlighted with Source Code Highlighter.


    How to change the context menu of text objects?

    You must set the delegate method. Here's how it is implemented in the program:

    - (NSMenu *)textView:(NSTextView *)view menu:(NSMenu *)menu forEvent:(NSEvent *)event atIndex:(NSUInteger)charIndex
    {
      NSMenuItem *spotlight = nil;
      NSMenuItem *google = nil;
      NSMenuItem *dictionary = nil;
      NSMenuItem *copy = nil;
      NSMenuItem *speech = nil;
      
      int count = [menu numberOfItems];
      
      for (int i = 0; i < count; i++)
      {
        SEL action = [[menu itemAtIndex:i] action];
        
        if (action == @selector(spotlight:))
        {
          spotlight = [[menu itemAtIndex:i] retain];
        }
        else if (action == @selector(_searchWithGoogleFromMenu:))
        {    
          google = [[menu itemAtIndex:i] retain];
        }
        else if (action == @selector(_lookUpDefiniteRangeInDictionaryFromMenu:))
        {
          dictionary = [[menu itemAtIndex:i] retain];      
        }
        else if (action == @selector(copy:))
        {
          copy = [[menu itemAtIndex:i] retain];      
        }
        else if (action == @selector(submenuAction:))
        {
          NSMenu *submenu = [[menu itemAtIndex:i] submenu];
          
          if (submenu)
          {
            if ([submenu numberOfItems] == 2)
            {
              if ([[submenu itemAtIndex:0] action] == @selector(startSpeaking:))
              {
                speech = [[menu itemAtIndex:i] retain];
              }
            }
          }      
        }
      }
      
      if (!copy)
      {
        if (spotlight) [spotlight release];
        if (google)  [google release];
        if (dictionary)  [dictionary release];
        if (speech)  [speech release];
        
        return menu;
      }
      
      [menu removeAllItems];
      if (spotlight) [menu addItem:spotlight], [spotlight release];
      if (google)  [menu addItem:google], [google release];
      if (dictionary)  [menu addItem:dictionary], [dictionary release];
      
      if ([menu numberOfItems] > 0) [menu addItem:[NSMenuItem separatorItem]];
      [menu addItem:copy], [copy release];
      
      if (speech)
      {
        [menu addItem:[NSMenuItem separatorItem]];
        [menu addItem:speech], [speech release];
      }
      
      return menu;
    }

    * This source code was highlighted with Source Code Highlighter.


    How to send requests (and receive answers) to online translation services (for example, Google, Microsoft)?

    You can use the standard NSURLConnection class. I preferred to use the third-party class GDataHTTPFetcher from the Google gdata-objectivec-client project. Working with an object of this class is very simple. Here is the request code from the program:

      NSString *sourceText = [originalText stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];  
      NSString *langs = [[NSString stringWithFormat:@"%@|%@", sourceLanguage, targetLanguage] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
      NSString *requestURL = [NSString stringWithFormat:@"%@&q=%@&langpair=%@", GoogleURL, sourceText, langs];
      NSURL *url = [NSURL URLWithString:requestURL];
      NSURLRequest* request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:20.0];
      
      fetcherG = [[GDataHTTPFetcher httpFetcherWithRequest:request] retain];
      [fetcherG beginFetchWithDelegate:self
            didFinishSelector:@selector(httpFetcher:finishedWithData:)
            didFailSelector:@selector(httpFetcher:didFail:)];

    * This source code was highlighted with Source Code Highlighter.


    Where GoogleURL is ajax.googleapis.com/ajax/services/language/translate?v=1.0

    Also popular now: