Pocket Translator is free utility for your Smartphone or PDA which translates words or texts from/to different languages using Google Translate online service.

Please note that Pocket Translator can translate words or texts only when you are connected to the Internet.

Supported Platforms

  • Windows Mobile 2003
  • Windows Mobile 5
  • Windows Mobile 6.0
  • Windows Mobile 6.1

Downloads

Download Pocket Translator

Screenshots

Pocket Translator for PocketPC

Next Article
Технический директор IT-Dimension, компании-разработчика кросс-платформенного программного обеспечения

Leave a Reply

Your email address will not be published. Required fields are marked *

П.

Пишем мобильный клиент для Google Translate на C++

В этот раз я хочу рассказать о том как работать с еще одним online-сервисом, а именно с сервисом online-переводов Google Translate.

Для работы с этим сервисом у Google есть свой программный интерфейс, а именно AJAX Language API for Translation And Detection. Именно его мы и будем использовать.

Для того чтобы осуществить online-перевод текста необходимо сделать http-запрос к сервису переводов, доступному по адресу:

http://ajax.googleapis.com/ajax/services/language/translate

Параметры, которые необходимо передать сервису:

  • v=1.0 – версия сервиса
  • q=<sometext> – URL-encoded текст для перевода.
  • langpair=<source_language>%7C<result_language> – пара названий языков: исходного и результирующего


Например для перевода текста “Hello World” с английского на русский строка запроса будет выглядеть так:

http://ajax.googleapis.com/ajax/services/language/translate?v=1.0&q=Hello%20World&langpair=en%7Cru

Ну вот, небольшой теоретический экскурс закончен, можно приступать к кодингу:
wxGoogleTranslate.h

#ifndef _WX_GOOGLE_TRANSLATE_H
#define _WX_GOOGLE_TRANSLATE_H

#include <wx/wx.h>

class wxGoogleTranslate
{
	/// \brief Language Info
	struct wxGoogleTranslateLanguageInfo
	{
		/// \brief Full language name
		wxString languageName;
		/// \brief Language code
		wxString languageCode;
	};

	/// \brief Stores information about all supported languages
	static wxGoogleTranslateLanguageInfo m_LanguageInfoArray[];
	/**
	\brief Parses JSON response from Google Translate service
	\param response contains JSON response from Google Translate service
	\param translatedText contains translated text if parsing of JSON response was correct
	\param translateionDetails contains additional information from Google Translate service
		   usually it is error message
    \param translationStatus contains parsing status (error code)
	\return true if translation and parsing was successfull, otherwise false
	*/
	static bool ParseJSONResponse(const wxString & response,
		wxString & translatedText,
		wxString & translateionDetails,
		int & translationStatus);
public:
	/// \brief Returns the list of all suported languages
	/// \param result array for storing language names
	static void GetLanguages(wxArrayString & result);
	/**
	\brief Returns language code by language name
	\param languageName language name
	\return language code on success or empty string on error
	*/
	static wxString GetLanguageCode(const wxString & languageName);
	/**
	\brief Translates given text with Google Translate service
	\param source string to translate
	\param result translation result
	\param sourceLanguageCode source language code
	\param resultLanguageCode destination language code
	\param translationDetails error message
	\param errorCode error code
	\return true on success, otherwise false
	*/
	static bool Translate(const wxString & source, 
		wxString & result, 
		const wxString & sourceLanguageCode, 
		const wxString & resultLanguageCode,
		wxString & translationDetails,
		int & errorCode);
};

#endif

Итак, как я уже писал выше, для того чтобы сформировать корректный URL запроса нам необходимо чтобы текст для перевода был URL-encoded. Для этоко пишем функцию URLEncode()

wxString HexFromInt(const int &value)
{
	wxString szHexHolder;

	if( value < 16)
		szHexHolder.Printf(wxT("0%x"), value );
	else
		szHexHolder.Printf(wxT("%x"), value );

	return szHexHolder.MakeUpper();
}

wxString URLEncode(const wxString &value)
{
	wxString szToReturn = wxT("");
	unsigned int nPos = 0;

	while( value.length() > nPos ) 
	{
		wxChar cChar = value.GetChar(nPos);

		if( (cChar >= wxT('0') && cChar <= wxT('9')) || 
			(cChar >= wxT('a') && cChar <= wxT('z')) || 
			(cChar >= wxT('A') && cChar <= wxT('Z')) || 
			(cChar == wxT('-')) || (cChar == wxT('@')) || 
			(cChar == wxT('*')) || (cChar == wxT('_')) )
		{
			szToReturn.Append( cChar );
		}
		else
		{
			switch( cChar )
			{
			case wxT(' '):  szToReturn.Append(wxT('+')); break;
			case wxT('\n'): szToReturn.Append(wxT("%0D%0A")); break;
			default:
				{
					szToReturn.Append(wxT("%"));
					szToReturn += HexFromInt( cChar );
				}
			}
		}
		nPos++;
	}
	return szToReturn;
}
&#91;/sourcecode&#93;
На самом деле большая часть приведенного выше кода позаимствована из библиотеки wxHTTPEngine, но, к сожалению, исходная реализация не работала с русскими символами и пришлось ее немного доработать напильником.
Так, с URL-encoding'ом разобрались, но это еще не все. Перед тем как формировать URL-encoded строку нам необходимо текст преобразовать в UTF-8. Для этого можно использовать метод <strong>wxString::ToUTF8()</strong>.
Список поддерживаемых сервисом языков можно найти на странице описания Google Language API. У нас в программе для этого будет массив структур, каждая из которых будет содержать полное название языка и его код (который можно будет передать в параметр <strong>languagepair</strong>):

wxGoogleTranslate::wxGoogleTranslateLanguageInfo 
	wxGoogleTranslate::m_LanguageInfoArray[] =
{
	{wxT("AFRIKAANS"),				wxT("af")},
	{wxT("ALBANIAN"),				wxT("sq")},
	{wxT("AMHARIC"),				wxT("am")},
	{wxT("ARABIC"),					wxT("ar")},
	{wxT("ARMENIAN"),				wxT("hy")},
	{wxT("AZERBAIJANI"),			wxT("az")},
	{wxT("BASQUE"),					wxT("eu")},
	{wxT("BELARUSIAN"),				wxT("be")},
	{wxT("BENGALI"),				wxT("bn")},
	{wxT("BIHARI"),					wxT("bh")},
	{wxT("BULGARIAN"),				wxT("bg")},
	{wxT("BURMESE"),				wxT("my")},
	{wxT("CATALAN"),				wxT("ca")},
	{wxT("CHEROKEE"),				wxT("chr")},
	{wxT("CHINESE"),				wxT("zh")},
	{wxT("CHINESE_SIMPLIFIED"),		wxT("zh-CN")},
	{wxT("CHINESE_TRADITIONAL"),	wxT("zh-TW")},
	{wxT("CROATIAN"),				wxT("hr")},
	{wxT("CZECH"),					wxT("cs")},
	{wxT("DANISH"),					wxT("da")},
	{wxT("DHIVEHI"),				wxT("dv")},
	{wxT("DUTCH"),					wxT("nl")},
	{wxT("ENGLISH"),				wxT("en")},
	{wxT("ESPERANTO"),				wxT("eo")},
	{wxT("ESTONIAN"),				wxT("et")},
	{wxT("FILIPINO"),				wxT("tl")},
	{wxT("FINNISH"),				wxT("fi")},
	{wxT("FRENCH"),					wxT("fr")},
	{wxT("GALICIAN"),				wxT("gl")},
	{wxT("GEORGIAN"),				wxT("ka")},
	{wxT("GERMAN"),					wxT("de")},
	{wxT("GREEK"),					wxT("el")},
	{wxT("GUARANI"),				wxT("gn")},
	{wxT("GUJARATI"),				wxT("gu")},
	{wxT("HEBREW"),					wxT("iw")},
	{wxT("HINDI"),					wxT("hi")},
	{wxT("HUNGARIAN"),				wxT("hu")},
	{wxT("ICELANDIC"),				wxT("is")},
	{wxT("INDONESIAN"),				wxT("id")},
	{wxT("INUKTITUT"),				wxT("iu")},
	{wxT("ITALIAN"),				wxT("it")},
	{wxT("JAPANESE"),				wxT("ja")},
	{wxT("KANNADA"),				wxT("kn")},
	{wxT("KAZAKH"),					wxT("kk")},
	{wxT("KHMER"),					wxT("km")},
	{wxT("KOREAN"),					wxT("ko")},
	{wxT("KURDISH"),				wxT("ku")},
	{wxT("KYRGYZ"),					wxT("ky")},
	{wxT("LAOTHIAN"),				wxT("lo")},
	{wxT("LATVIAN"),				wxT("lv")},
	{wxT("LITHUANIAN"),				wxT("lt")},
	{wxT("MACEDONIAN"),				wxT("mk")},
	{wxT("MALAY"),					wxT("ms")},
	{wxT("MALAYALAM"),				wxT("ml")},
	{wxT("MALTESE"),				wxT("mt")},
	{wxT("MARATHI"),				wxT("mr")},
	{wxT("MONGOLIAN"),				wxT("mn")},
	{wxT("NEPALI"),					wxT("ne")},
	{wxT("NORWEGIAN"),				wxT("no")},
	{wxT("ORIYA"),					wxT("or")},
	{wxT("PASHTO"),					wxT("ps")},
	{wxT("PERSIAN"),				wxT("fa")},
	{wxT("POLISH"),					wxT("pl")},
	{wxT("PORTUGUESE"),				wxT("pt-PT")},
	{wxT("PUNJABI"),				wxT("pa")},
	{wxT("ROMANIAN"),				wxT("ro")},
	{wxT("RUSSIAN"),				wxT("ru")},
	{wxT("SANSKRIT"),				wxT("sa")},
	{wxT("SERBIAN"),				wxT("sr")},
	{wxT("SINDHI"),					wxT("sd")},
	{wxT("SINHALESE"),				wxT("si")},
	{wxT("SLOVAK"),					wxT("sk")},
	{wxT("SLOVENIAN"),				wxT("sl")},
	{wxT("SPANISH"),				wxT("es")},
	{wxT("SWAHILI"),				wxT("sw")},
	{wxT("SWEDISH"),				wxT("sv")},
	{wxT("TAJIK"),					wxT("tg")},
	{wxT("TAMIL"),					wxT("ta")},
	{wxT("TAGALOG"),				wxT("tl")},
	{wxT("TELUGU"),					wxT("te")},
	{wxT("THAI"),					wxT("th")},
	{wxT("TIBETAN"),				wxT("bo")},
	{wxT("TURKISH"),				wxT("tr")},
	{wxT("UKRAINIAN"),				wxT("uk")},
	{wxT("URDU"),					wxT("ur")},
	{wxT("UZBEK"),					wxT("uz")},
	{wxT("UIGHUR"),					wxT("ug")},
	{wxT("VIETNAMESE"),				wxT("vi")},
	{wxT("UNKNOWN"),				wxEmptyString}
};

Для получения списка языков будет использоваться метод wxGoogleTranslate::GetLanguages()

void wxGoogleTranslate::GetLanguages(wxArrayString & result)
{
	result.Clear();
	int count = sizeof(m_LanguageInfoArray) / 
		sizeof(wxGoogleTranslateLanguageInfo);
	for(int i = 0; i < count; i++)
	{
		result.Add(m_LanguageInfoArray&#91;i&#93;.languageName);
	}
}
&#91;/sourcecode&#93;
Для получения кода языка предназначен метод <strong>wxGoogleTranslate::GetLanguageCode()</strong>:

wxString wxGoogleTranslate::GetLanguageCode(const wxString & languageName)
{
	int count = sizeof(m_LanguageInfoArray) / 
		sizeof(wxGoogleTranslateLanguageInfo);
	for(int i = 0; i < count; i++)
	{
		if(m_LanguageInfoArray&#91;i&#93;.languageName.Lower().IsSameAs(
			languageName.Lower()))
		{
			return m_LanguageInfoArray&#91;i&#93;.languageCode;
		}
	}
	return wxEmptyString;
}
&#91;/sourcecode&#93;
Теперь можно реализовывать непосредственно метод для перевода текста:
&#91;sourcecode language="cpp"&#93;
bool wxGoogleTranslate::Translate(const wxString & source, 
		wxString & result, 
		const wxString & sourceLanguageCode, 
		const wxString & resultLanguageCode,
		wxString & translationDetails,
		int & errorCode)
{
	do
	{
		wxString urlEncodedSource = 
			URLEncode(wxString::FromAscii(source.ToUTF8()));
		wxString srcURL = wxString::Format(
			wxT("%s?v=1.0&q=%s&langpair=%s%%7C%s"),
			wxT("http://ajax.googleapis.com/ajax/services/language/translate"),
			urlEncodedSource.GetData(),
			sourceLanguageCode.GetData(),
			resultLanguageCode.GetData());
		wxURL url = srcURL;
		if(url.GetError() != wxURL_NOERR) break;
		wxInputStream * in = url.GetInputStream();
		if(!in) break;
		wxString response;
		wxStringOutputStream out(&response);
		in->Read(out);
		wxDELETE(in);
		if(response.IsEmpty()) break;
		if(!wxGoogleTranslate::ParseJSONResponse(response, result, 
			translationDetails, errorCode)) break;
		return true;
	}
	while(false);
	return false;
}

Результат запроса приходит в формате JSON. В стандартной поставке wxWidgets библиотеки для парсинга JSON нет, зато есть сторонняя библиотека wxJSON, которую мы и будем использовать.
Формат ответа от сервиса Google Translate:

{"responseData": {"translatedText":"sometext"}, "responseDetails": "sometext", "responseStatus": 200}

Где

  • translatedText – переведенный текст
  • responseDetails – дополнительная информация от сервиса (сообщение об ошибке)
  • responseStatus – код ошибки

Метод для парсинга ответа сервиса:

bool wxGoogleTranslate::ParseJSONResponse(const wxString & response,
		wxString & translatedText,
		wxString & translateionDetails,
		int & translationStatus)
{
	do
	{
		wxJSONValue  root;
		wxJSONReader reader;
		if(reader.Parse(response, &root) > 0) break;
		translatedText = 
			root[wxT("responseData")][wxT("translatedText")].AsString();
		translateionDetails = 
			root[wxT("responseDetails")].AsString();
		translationStatus = 
			root[wxT("responseStatus")].AsInt();
		return true;
	}
	while(false);
	return false;
}

Ну вот, работу над классом переводчика закончили. Теперь посмотрим как его использовать:

void wxGoogleTranslateClientMainFrame::OnTRANSLATEClick( wxCommandEvent& event )
{
	do
	{
		wxString result;
		wxString details;
		int errorCode(0);
		int sourceLangselection = m_SourceLanguageChoice->GetSelection();
		int resultLangselection = m_ResultLanguageChoice->GetSelection();
		if((sourceLangselection < 0) || (resultLangselection < 0)) break;
		if(wxGoogleTranslate::Translate(m_SourceTextCtrl->GetValue(), 
			result, 
			wxGoogleTranslate::GetLanguageCode(
				m_SourceLanguageChoice->GetString(sourceLangselection)), 
			wxGoogleTranslate::GetLanguageCode(
			m_ResultLanguageChoice->GetString(resultLangselection)), 
				details, errorCode))
		{
			m_ResultTextCtrl->SetValue(result);
		}
		else
		{
			wxMessageBox(wxString::Format(_("Erorr occured: %s"), details.GetData()));
		}
	}
	while(false);
}

Хотелось бы отметить вот что: для загрузки ответа от сервиса используется класс wxURL. Используется синхронно, поэтому работа вызывающего потока приложения блокируется до тех пор пока загрузка не будет завершена.
Использование же класса переводчика заключается в вызове метода Translate(), никаких дополнительных действий по инициализации или деинициализации не требуется.

Исходный код библиотеки wxGoogleTranslate, а также исходный код и исполняемые файлы примера для Windows NT/2000/XP/Vista и для Windows Mobile 2003/5/6 можно загрузить здесь.

Р.

Работаем с LED-индикаторами устройства под управлением Windows Mobile

Для того чтобы управлять LED-индикаторами устройства, в Windows Mobile предусмотрено специальное API:

BOOL WINAPI NLedSetDevice(UINT nDeviceId, void* pInput);

Первый параметр, nDeviceID указывает на то, какие данные передаются в параметре pInput. Для того чтобы установить состояние LED-индикатора, параметр nDeviceID должен иметь значение NLED_SETTINGS_INFO_ID, а в качестве параметра pInput необходимо передать указатель на структуру NLED_SETTINGS_INFO, содержащую информацию о новом состоянии LED-индикатора.

struct NLED_SETTINGS_INFO {
UINT LedNum;
INT OffOnBlink;
LONG TotalCycleTime;
LONG OnTime;
LONG OffTime;
INT MetaCycleOn;
INT MetaCycleOff;
};
  • LedNum – содержит индекс LED-индикатора (zero-based).
  • OffOnBlink – содержит новое состояние индикатора (0 – выключен, 1 – включен, 2 – мигающий
  • TotalCycleTime – длительность цикла мерцания в миллисекундах
  • OnTime – длительность включенного состояния индикатора при мерцании
  • OffTime – длительность выключенного состояния индикатора при мерцании
  • MetaCycleOn – количество ON-циклов
  • MetaCycleOff – количество OFF-циклов

Вобще описание назначения последних двух полей структуры вводит меня в недоумение. В MSDN по этому поводу всего две скупые фразы “Number of on blink cycles.” и “Number of off blink cycles.” без какого-либо дальнейшего пояснения.

Для того чтобы получить количество LED-индикаторов в системе можно воспользоваться функцией NLedGetDeviceInfo:

BOOL WINAPI NLedGetDeviceInfo(UINT nInfoId, void* pOutput);

В качестве первого параметра необходимо передать значение NLED_COUNT_INFO_ID, в качестве второго параметра – указатель на структуру NLED_COUNT_INFO, которая, в случае успешного завершения работы функции, будет содержать количество индикаторов.

Ну вот, с теоретической частью закончили, теперь перейдем к рассмотрению простенького примера. А в качестве примера у нас будет небольшая библиотека-обертка над описанным выше API.

wxMobileLED.h

#ifndef _WX_MOBILE_LED_H
#define _WX_MOBILE_LED_H

class wxMobileLEDImpl;

class wxMobileLED
{
	wxMobileLEDImpl * m_Impl;
public:
	wxMobileLED();
	~wxMobileLED();
	size_t GetCount();
	bool SetLED(size_t index, bool value, bool blink = false);
};

#endif

wxMobileLED.cpp

#include "wxMobileLED.h"
#if defined(__WXWINCE__)
#include "wxMobileLEDImplWinCE.h"
#else
#endif

wxMobileLED::wxMobileLED()
{
	m_Impl = 
#if defined(__WXWINCE__)
		new wxMobileLEDImplWinCE;
#else
		NULL;
#endif
}

wxMobileLED::~wxMobileLED()
{
	if(m_Impl) delete m_Impl;
}

size_t wxMobileLED::GetCount()
{
	if(m_Impl)
	{
		return m_Impl->GetCount();
	}
	return 0;
}

bool wxMobileLED::SetLED(size_t index, bool value, bool blink)
{
	if(m_Impl)
	{
		return m_Impl->SetLED(index, value, blink);
	}
	return false;
}

wxMobileLEDImpl.h

#ifndef _WX_MOBILE_LED_IMPL_H
#define _WX_MOBILE_LED_IMPL_H

class wxMobileLEDImpl
{
public:
	virtual size_t GetCount() = 0;
	virtual bool SetLED(size_t index, bool value, bool blink = false) = 0;
};

#endif

wxMobileLEDImplWinCE.h

#ifndef _WX_MOBILE_LED_IMPL_WINCE_H
#define _WX_MOBILE_LED_IMPL_WINCE_H

#include "wxMobileLEDImpl.h"

class wxMobileLEDImplWinCE : public wxMobileLEDImpl
{
public:
	virtual size_t GetCount();
	virtual bool SetLED(size_t index, bool value, bool blink = 0);
};

#endif

wxMobileLEDImplWinCE.cpp

#include "wxMobileLEDImplWinCE.h"
#include <windows.h>
#include <NLed.h>

size_t wxMobileLEDImplWinCE::GetCount()
{
#if defined(__WXWINCE__) && (UNDER_CE >= 0x500)
	NLED_COUNT_INFO count = {0};
	NLedGetDeviceInfo(NLED_COUNT_INFO_ID,&count); 
	return count.cLeds;
#else
	return 0;
#endif
}

bool wxMobileLEDImplWinCE::SetLED(size_t index, bool value, bool blink)
{
#if defined(__WXWINCE__) && (UNDER_CE >= 0x500)
	do
	{
		if(index >= GetCount()) break;
		NLED_SETTINGS_INFO info;
		ZeroMemory(&info, sizeof(NLED_SETTINGS_INFO));
		info.LedNum = index;
		info.OffOnBlink = value ? (blink ? 2 : 1) : 0;
		return (NLedSetDevice(NLED_SETTINGS_INFO_ID, &info) == TRUE);
	}
	while(false);
#endif
	return false;
}

Пример использования библиотеки:


wxMobileLED m_MobileLED;

...
void wxMobileLEDTestMainFrame::FillLEDList()
{
	size_t ledCount = m_MobileLED.GetCount();
	for(size_t i = 0; i < ledCount; i++)
	{
		int item = m_LEDList->Append(wxString::Format(wxT("LED %i"), i+1));
	}
}

void wxMobileLEDTestMainFrame::UpdateLEDs()
{
	for(size_t i = 0; i < m_LEDList->GetCount(); i++)
	{
		bool value = m_LEDList->IsChecked(i);
		if(!m_MobileLED.SetLED(i, value, m_BlinkCheckBox->GetValue()))
		{
			wxLogTrace(wxTraceMask(), _("Unable to turn LED #%i %s"), i, 
				value ? _("ON") : _("OFF"));
		}
	}
}

Исходный код примера для wxWinCE, а также исполняемый файл для Windows Mobile 6 можно взять здесь.

PS: Хотя описанное выше API предназначено для управления состоянием LED-индикаторов и на эмуляторе действительно управляет ими, но на реальном устройстве (ETEN Glofiish X800 под управлением Windows Mobile 6) включение/віключение индикатора с индексом 1 приводит к включению/віключению вибро. Мая шоке %).