Pull to refresh

Переlator

Reading time9 min
Views20K
По ходу своей работы я сталкиваюсь с маленькими задачами, которые отнимают много времени (при решении «в лоб»). Иногда получается найти средства для быстрого решения этих задач, иногда нет. Во втором случае, чаще всего, я быстренько пишу собственные маленькие программы, которые позволяют максимально упросить решение задачи.

Недавно столкнулся с одной такой задачей. Всё чаще стала возникать необходимость перевести какой-то текст. То на иврите нужно перевести абзац, то на китайском сайте нужно было почитать обсуждение, то при написании письма зарубежным коллегам не получается перевести «хитрое» предложение — приходится обращаться к онлайн сервисам перевода («подглядеть», что подскажут). Я пользовался сервисами ПРОМТ и Google. Такой подход мне начал надоедать, и я за пару вечеров набросал контекстный переводчик, который использует сразу три сервиса от компаний: Google (Google Translator), Microsoft (Bing Translator), ПРОМТ (мобильная версия).

image

Уверен, что мои наработки кому-то окажутся полезными.

Эту мини-статью я разделю на две части. Первая посвящена тем, кто хочет просто установить программу и пользоваться ей. А вторая, тем только делает первые шаги в освоение разработки «под» Mac OS X и iPhone (сделали первую программа «Конвертер» по руководству от Apple, но уже имеющие желание писать коммерческое ПО).


Переlator — это простой, но достаточно удобный контекстный переводчик для Mac OS X. Возможны баги, сбои — детально я его не тестировал (не было нужды), но у меня он несколько дней работает нормально.

Компания Apple в Mac OS X 10.6 (Snow Leopard) наконец-то обратила внимание на функционал Services (Службы) и очень хорошо «причесала» его. Переlator базируется на этом функционале.

УСТАНОВКА

1). Скопируйте Translation.service в папку Services:

[ДОМАШНЯЯ ПАПКА]/Библиотеки/Services — если сервис нужен только Вам.
/Библиотеки/Services — если сервис нужен всем пользователям в системе.

Если папки Services не оказалось в необходимом месте, то просто создайте её.

image

2). Два раза щёлкаем мышкой по сервису (запускаем) или выполняем выход и вход в систему.

3). Открываем Системные настройки > Клавиатура > Службы. Ставим галочку напротив «Перевести» («Translate») и задаём удобное клавиатурное сокращение.

image

4). Всё. Контекстный переводчик полностью готов к работе.

ИСПОЛЬЗОВАНИЕ

В любой программе, которая поддерживает Службы (Safari, Mail, Skype, iChat, TextEdit, Pages и пр.) выделяем текст, нажимаем правой кнопкой мыши для вызова контекстного меню и выбираем «Перевести» («Translate») — под курсором откроется окно с переводом. Или выделите текст и нажмите заданное клавиатурное сокращение.

image
image

Важное замечание… Некоторые программы (особенно кросс-платформенные) не поддерживают функционал Службы.

Переlator для каждого перевода использует собственное окно. Т.е. предыдущий окно с предыдущим перевод не закрывается при переводе нового текста.

Вы можете настроить удобный для Вас размер окна переводчика. Достаточно просто подстроить окно под необходимый размер, и все следующие окна будет идентичного размера.

Провайдер услуги перевода автоматически сохраняется. Например, если Вы в последнем окне выбрали Microsoft, то следующий перевод автоматически отобразить перевод от Microsoft.

image

В настройках программы Вы можете задать размер шрифта перевода и пару языков для перевода по умолчанию.

image

Если язык не поддерживается провайдером, мы увидим соответствующее сообщение.

Скачать программу можно по ссылке: http://www.yuriev.info/translator/translator.zip
Системные требования: Mac OS X 10.6 и выше

ОГРАНИЧЕНИЯ

В программа не позволяет переводить очень длинные тексты (в техническом смысле длина запроса не должна превышать 2000 символов). В программе используются методы GET, а не POST.

В программе используется мобильный вариант ПРОМТ (m.translate.ru), которые может переводить только небольшие абзацы.

ДЛЯ НАЧИНАЮЩИЙ РАЗРАБОТЧИКОВ

Я собрал тут ряд банальных и не очень вопросов (которые актуальны для Переlator) и дал на них ответы.

Как создавать HUD интерфейс?

Компания Apple для разработчиков представляет только лишь HUD панель. Все элементы пользователь должен создавать самостоятельно или использовать готовые библиотеки. Я использовал BGHUDAppKit.

Как сохранить и загрузить определённые настройки программы?

Используйте класс NSUserDefaults.

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

* This source code was highlighted with Source Code Highlighter.


Как задать содержимое NSPopUpButton?

Например, так:

  [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.


Как задать цвет текста на кнопке?

  [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.


Как применить CoreImage эффекты к окну (например, сделать размытие как Windows)?

Без использования приватного API не обойтись.

Объявляем:

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.


Задаём фильтр:

  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.


Убираем фильтр:

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

* This source code was highlighted with Source Code Highlighter.


Как получить доступ к NSView объекту заголовка окна (для размещения там каких-то дополнительных элементов, например, замочка, как в Safari)?

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

* This source code was highlighted with Source Code Highlighter.


Как получить текущие координаты курсора мыши?

  NSPoint point = [NSEvent mouseLocation];

* This source code was highlighted with Source Code Highlighter.


Как изменить шрифт у всего содержимого объекта NSTextView?

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

* This source code was highlighted with Source Code Highlighter.


Как программно задать начальную позицию в NSTextView (скроллинг в самое начало)?

  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.


Как скрыть какой-нибудь объект класса NSView (например, кнопку)?

  [object setHidden:YES];    

* This source code was highlighted with Source Code Highlighter.


Как изменить контекстное меню текстовых объектов?

Нужно задать метод делегата. Вот как это реализовано в программе:

- (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.


Как отправлять запросы (и получать ответы) к онлайн-сервисам перевода (например, Google, Microsoft)?

Можно воспользоваться стандартным классом NSURLConnection. Я предпочёл воспользоваться сторонним классом GDataHTTPFetcher из проекта gdata-objectivec-client компании Google. Работать объектом этого класса очень просто. Вот код запроса из программы:

  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.


Где GoogleURL — это ajax.googleapis.com/ajax/services/language/translate?v=1.0
Tags:
Hubs:
Total votes 94: ↑86 and ↓8+78
Comments60

Articles