Mac OS X

индекс
118,30

Переlator

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

Недавно столкнулся с одной такой задачей. Всё чаще стала возникать необходимость перевести какой-то текст. То на иврите нужно перевести абзац, то на китайском сайте нужно было почитать обсуждение, то при написании письма зарубежным коллегам не получается перевести «хитрое» предложение — приходится обращаться к онлайн сервисам перевода («подглядеть», что подскажут). Я пользовался сервисами ПРОМТ и 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
+78
4 марта 2010, 10:46
85

комментарии (54)

+1
Isis #
Классно. Вы подали мне идею, спасибо =)
+10
Kyrie1965 #
Уверен, что буду кусать локти, когда Вы разбогатеете на этой идее :).
+1
emostar #
хочу такое для линукса, незаменимая вещь
+1
Kyrie1965 #
Если захотите написать самостоятельно для Linux, то без проблем могу дать все исходные коды проекта Переlator. Вряд ли они будут полезны (относительно Linux), но всё же…
0
bagyr #
StarDict/QStarDict вроде умеют переводить выделенное слово по хоткею, доступ к онлайн-сервисам там есть точно, не уверен только насчет быстрой смены словаря/направления перевода. Для добавления пункта меню с переводом в произвольное поле ввода, видимо, придется хачить GTK/Qt или каждое отдельное приложение.
+2
switchON #
Перенесите в тематический блог. Этот пост должен появиться на главной.
+1
Kyrie1965 #
Я тут новенький и пока ещё разбираюсь, как это сделать. Как мне подсказали, нужно +15 к посту. Верно?
+1
Kyrie1965 #
Отвечаю сам себе. Верно :).
+1
Chater #
Низкий поклон Вам:)
0
Dvulikiy #
Присоединяюсь, дошли руки до апгрейда на 10.6, знаю что долго «руки шли» но всё же. Спасибо ещё раз.
НЛО прилетело и опубликовало эту надпись здесь
+2
chubr #
Просто отлично! Спасибо Вам
Жаль только Chrome не поддерживает данный функционал(
+1
Kyrie1965 #
Сразу напишу список распространённого ПО, которое «криво» или вообще не работает с функционалом Службы в Mac OS X:

Firefox
Chrome
MS Office for Mac
NeoOffice
AbiWord
+1
VadimUA #
В iWork я тоже не могу добиться появления этого пункта :(
+1
Kyrie1965 #
Да, в iWork пункт «Перевести» не появляется в контекстном меню. Но клавиатурное сокращение и меню [ПРОГРАММА] > Службы > Перевести работают.

Я думаю, что в каком-то из обновлений (или в будущей версии iWork) это поправят. Контекстный функционал для Служб появился только в 10.6. Видимо, в iWork это не учли.

+2
VadimUA #
Вчера поставил и уже пользуюсь. Очень удобную вещь вы сделали. Спасибо!

Только единственное… не у всех пользователей есть папка Services. И при отсутствии таковой её необходимо создать.
+2
Kyrie1965 #
Да, всё верно.

По умолчанию в корневой папке Библиотеки нет папки Services. Её необходимо создать, если программой будут пользоваться все пользователи, зарегистрированные в ОС.
+2
VadimUA #
Ну и в папке [USER_NAME]/Library/ она кстати тоже не у всех есть.

Вообщем это я к тому, чтобы пометить это в вашем посте (дабы избежать подобных вопросов от пользователей).
+2
Kyrie1965 #
Пометил.
+1
AzriMan #
Интересно, я один несколько раз пытался кликнуть на кнопки Google, Microsoft, ПРОМТ?
+3
b0fh #
автору софтины респект.
вечермо обязательно поставлю, тк функицонал сделан удобно.
немного напоминает гугле транслейт, но сделано умнее.
0
absinthe #
Спасибищще!
0
VadimUA #
А если еще «прикрутить» его к встроенному Dictionary в котором стоят к примеру кастомные словари (скажем для детального перевода конкретного слова) — то откусите хороший кусок от пирога «Translate software for Mac».
+2
Kyrie1965 #
Открою маленький секрет… в большинстве своём пользовательские словари (у русскоязычных пользователей) для Apple Dictionary — это перекомпилированные словари от ABBYY Lingvo, сделанные с помощью DSLConverter. Словари для основных европейских языков поддерживают морфологию (словоформы встраиваются в сами словари) и содержат озвучивание. Естественно, такие словари не являются легальными.

DSLConverter это моя же программа.

А если копнуть ещё раньше, то был когда-то такой, не побоюсь этого слова, говно-продукт (я о качестве самой оболочки) МультиЛекс для Mac OS X — первый более-менее нормальный словарь для Mac OS X от компании МедиаЛингва. Это я тоже делал…

И сразу финальная мысль. Во-первых, разработчик не может делать словари для Apple Dictionary на базе Интернет-сервисов, только на базе статических баз. Во-вторых, это не коммерческий проект и развивать я его не стремлюсь — этот кусок пирога мне не интересен :).

0
ruzzz #
А вы только под макОС разработкой занимаетесь?
+1
Kyrie1965 #
Mac OS X и iPhone OS.

Последний год в большей степени занимаюсь iPhone OS.
0
shimdim #
возможно ли это заставить работать на 10.5?
помогите пользователям PPC…
0
Kyrie1965 #
Если бы это был коммерческий проект, то, естественно, была бы поддержка 10.5. А так это просто маленький проект для себя и тех, кому он окажется полезен. Под 10.5 оптимизировать не планирую.
0
Dvulikiy #
А жаль, очень жаль… :(
0
Liksys #
Для линукса:
code.google.com/p/lightlang
0
sanchower #
Что-то не получается у меня придумать сочетание клавиш. Вернее сочетание-то вбиваю, а вот не вызывает оно перевод, хоть если кликать по контекстному меню, все отлично.
0
Kyrie1965 #
Единственный вариант — подбирать. Сочетание клавиш для Служб не могут перекрывать сочетания клавиш внутри активной программы. Сочетание может работать в одной программе, но не работать в другой. Тут только подбирать.
0
sanchower #
А Вы какое сочетание используете?
0
Kyrie1965 #
Вообще не использую (но установлено Comand+Shift+Y). Только контекстное меню.
0
GreenAngel #
А как насчёт оперы?
0
Kyrie1965 #
Опера из той же оперы — сервисы не поддерживает, насколько я знаю.
0
baxtep2 #
жаль в chrome не работает.
привыкаю к расширению Auto-Translate
0
smartov #
Я бы вам сразу +5 накликал, если бы мог!
0
mataleao #
А как лишние языки убрать из выпадающего меню? Не запоминает язык в чью сторону происходит перевод. При быстрой работе очень утомляет каждый раз скроллить такой длиннющий список.
0
Kyrie1965 #
Никак не убрать.

Странно, надо смотреть, у меня всё запоминает.
0
Astashov_Anton #
Класс! Особенно спасибо за короткий FAQ по Objective-C!
0
ukrainets #
У меня Mac OS 10.5 :( придется обновлять…
0
den26 #
Вообще лучший словарь multitran.ru А вообще идея интересная, скачаю опробую программу
0
Kyrie1965 #
Словарь и полнотекстовый переводчик — это абсолютно разные инструменты.
0
den26 #
Ясно. полнотекстовые переводчики не интересуют — ужасно переводят.
0
Allpa #
А-бал-деть, других слов просто нет :) Потрясающе! Великолепно! Браво!
Короче, Королева в восхищении© :)
Спасибо Вам за эту прекрасную программку — это именно то, чего мне так не хватало на макоси!
0
Paul #
У меня по коду вопрос — вы autorelease из каких соображений не используете?
0
Kyrie1965 #
По какому коду? Где не использую?
+1
Paul #
NSMutableAttributedString *colorTitle = [[NSMutableAttributedString alloc] initWithAttributedString:[contactButton attributedTitle]];
// ...
[colorTitle release];


Вместо

NSMutableAttributedString *colorTitle = [[[NSMutableAttributedString alloc] initWithAttributedString:[contactButton attributedTitle]] autorelease];


Ну и дальше у вас для каждого меню айтема по 2 раза release вызывается в разных ветках, этого можно было бы избежать если бы вы написали
menuItem = [[[menu itemAtIndex:i] retain] autorelease];
0
Kyrie1965 #
Я придерживаюсь правила «use release when you can and autorelease when you must» (стараюсь придерживаться, но иногда халтурю). Формально, autorelease — это тот же release, но с задержкой, следовательно с большим временным потреблением памяти для программы (и большим потреблением процессорных ресурсов требующихся для временных обработок пула). Это особенно актуально для устройств с небольшим количеством памяти c iOS.

autorelease упрощает написание кода для разработчика, но работу самой программы лучше не делает. Разработчик сам выбирает путь.
0
Kyrie1965 #
Вот и дошла очередь до iPhone/iPad — Ультра Переводчик:
community.livejournal.com/ru_iphone/2667329.html

0
Dexter_Holland #
Отличная софтина, спасибо :)
0
flake #
Интересно было бы добавить поддержку multitran.ru, для одиночных слов правда он только годен. На зато в плане возможных значений и интерпретаций просто КОРОЛЬ!

Давно мечтаю о контекстном мультитране, под виндой они делали какое-то убожество, но оно не вылетало постоянно и жутко тормозило. Я в итоге остановился на snippet'е самостоятельно сделанном для safari — выделил, и нажал кнопку в букмарк баре, но работает только в браузере.
0
flake #
Да, забыл спасибо сказать :) Отличный сервис. Вот переставил систему и пришлось лезть искать, чтобы восстановить, благо запомнил что на хабре встречал.

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