Пере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
    Support the author
    Share post
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 60

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

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

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

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

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

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

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

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

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

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

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

                                  Последний год в большей степени занимаюсь iPhone OS.
                              0
                              возможно ли это заставить работать на 10.5?
                              помогите пользователям PPC…
                                0
                                Если бы это был коммерческий проект, то, естественно, была бы поддержка 10.5. А так это просто маленький проект для себя и тех, кому он окажется полезен. Под 10.5 оптимизировать не планирую.
                                  0
                                  А жаль, очень жаль… :(
                              • UFO just landed and posted this here
                                  0
                                  Что-то не получается у меня придумать сочетание клавиш. Вернее сочетание-то вбиваю, а вот не вызывает оно перевод, хоть если кликать по контекстному меню, все отлично.
                                    0
                                    Единственный вариант — подбирать. Сочетание клавиш для Служб не могут перекрывать сочетания клавиш внутри активной программы. Сочетание может работать в одной программе, но не работать в другой. Тут только подбирать.
                                      0
                                      А Вы какое сочетание используете?
                                        0
                                        Вообще не использую (но установлено Comand+Shift+Y). Только контекстное меню.
                                    0
                                    А как насчёт оперы?
                                      0
                                      Опера из той же оперы — сервисы не поддерживает, насколько я знаю.
                                      0
                                      жаль в chrome не работает.
                                      привыкаю к расширению Auto-Translate
                                        0
                                        Я бы вам сразу +5 накликал, если бы мог!
                                          0
                                          А как лишние языки убрать из выпадающего меню? Не запоминает язык в чью сторону происходит перевод. При быстрой работе очень утомляет каждый раз скроллить такой длиннющий список.
                                            0
                                            Никак не убрать.

                                            Странно, надо смотреть, у меня всё запоминает.
                                            0
                                            Класс! Особенно спасибо за короткий FAQ по Objective-C!
                                              0
                                              У меня Mac OS 10.5 :( придется обновлять…
                                                0
                                                Вообще лучший словарь multitran.ru А вообще идея интересная, скачаю опробую программу
                                                  0
                                                  Словарь и полнотекстовый переводчик — это абсолютно разные инструменты.
                                                    0
                                                    Ясно. полнотекстовые переводчики не интересуют — ужасно переводят.
                                                  0
                                                  А-бал-деть, других слов просто нет :) Потрясающе! Великолепно! Браво!
                                                  Короче, Королева в восхищении© :)
                                                  Спасибо Вам за эту прекрасную программку — это именно то, чего мне так не хватало на макоси!
                                                    0
                                                    У меня по коду вопрос — вы autorelease из каких соображений не используете?
                                                      0
                                                      По какому коду? Где не использую?
                                                        +1
                                                        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
                                                          Я придерживаюсь правила «use release when you can and autorelease when you must» (стараюсь придерживаться, но иногда халтурю). Формально, autorelease — это тот же release, но с задержкой, следовательно с большим временным потреблением памяти для программы (и большим потреблением процессорных ресурсов требующихся для временных обработок пула). Это особенно актуально для устройств с небольшим количеством памяти c iOS.

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

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

                                                        Давно мечтаю о контекстном мультитране, под виндой они делали какое-то убожество, но оно не вылетало постоянно и жутко тормозило. Я в итоге остановился на snippet'е самостоятельно сделанном для safari — выделил, и нажал кнопку в букмарк баре, но работает только в браузере.
                                                          0
                                                          Да, забыл спасибо сказать :) Отличный сервис. Вот переставил систему и пришлось лезть искать, чтобы восстановить, благо запомнил что на хабре встречал.
                                                          0
                                                          Отличная работа, спасибо!
                                                            0
                                                            Google и Prompt не работают.
                                                              +1
                                                              ПРОМТ уже кучку лет как не работе, Google уже 2 года не работает в этой версии. Уже 3 года в Mac App Store лежит версия, в которой всё работает.
                                                                0
                                                                Спасибо, я что-то слоупочу.
                                                                  0
                                                                  мммм, что то я не могу его найти, не могли бы вы дать ссылку?
                                                                0
                                                                Статься старая, программа не работает, к сожалению автор забил на это. В епп сторе тоже все плачут что ничего не работает. image

                                                                Only users with full accounts can post comments. Log in, please.