четверг, 2 января 2014 г.

Несколько слов о локализации ПО

Решил написать несколько слов о локализации ПО, а именно о тех вещах, с которыми столкнулся я сам. В тексте используется Qt-специфичные слова и методы перевода, хотя это не особо важно. Без лишних вступлений перейдём сразу к сути:
  • не расставляйте знаки препинания, да и вообще не воздействуйте на структуру предложения программно. Например, у вас в одном месте используется текст "Prefix", в другом - "Prefix:".  Чтобы сэкономить на спичках вы можете написать в первом месте tr("Prefix"), во втором - tr("Prefix") + ':', таким образом в файле перевода строка "Prefix" встретится только один раз. Это неверно, потому что в некоторых языках, например, во французском, перед двоеточием принято ставить пробел. Написав tr("Prefix") + ':' вы сделаете неприятный сюрприз для французских пользователей;
  • переводческие бюро, которые заявляют об услуге локализации ПО, часто даже не знают что такое XLIFF или .po;
  • ни одна переводческая фирма не даст отличный результат для текста со специфичными для какой-то области словами. Особенно для текста со сленговыми словами, которые понимают только работники данной области. Например, попробуйте перевести с английского глагол "untar" (UNIX-специфичный сленг) - вы даже не найдете его в словаре;
  • гарантированный результат качества перевода даст только индивидуальная работа с переводчиком, но и стоит это соответственно;
  • вы можете использовать онлайн сервисы для перевода вашего проекта добровольцами, например Transifex. Но если ваш проект не слишком популярен, то маловероятно, что добровольцы его переведут хотя бы на три языка;
  • на том же сервисе Transifex вы можете за деньги заказать перевод своего проекта в коммерческих сервисах Gengo и Texmaster. Gengo имеет больше языков и переводит довольно быстро (обычно в течение часа-двух), но Textmaster по моим субъективным ощущениям переводит качественнее, хоть стоит дешевле, но и переводит в течение суток-двух;
  • заказанный за деньги перевод на Transifex всё равно нужно вычитывать;
  • чтобы перевести небольшой текст на платной основе можно воспользоваться коммерческими онлайн переводчиками типа Gengo, Textmaster или Alconst Nitro, и его всё равно нужно будет вычитывать.

понедельник, 11 ноября 2013 г.

Сокращение размера собственного инсталлятора Qt4 (компилятор MinGW)

Если вы собрали свой инсталлятор Qt4 для каких-то своих целей, то вероятно обратили внимание на то, что в каталоге сборки Qt в подкаталогах bin и lib лежат дублирующие друг друга наборы Qt библиотек - bin\QtCore4.dll, lib\QtCore4.dll и т.д. Если вы собирали Qt с флагом -debug-and-release, то один такой набор занимает порядка 500 Mb, то есть ваш инсталлятор установит лишние 500 Mb файлов, и сам будет больше на 50-60 "лишних" мегабайт. При использовании MinGW мы можем решить эту проблему никак не трогая проекта, который будет собираться напротив этой сборки Qt.

Сперва удаляем все Qt-шные dll из подкаталога lib. Библиотеки Qt теперь останутся только в подкаталоге bin.

При линковке вашего проекта, основанного на Qt, линкер будет искать библиотеки Qt именно в почищенном нами lib. Данную проблему можно решить заданием флагов QMAKE_LFLAGS в вашем проекте (QMAKE_LFLAGS += -L <ПУТЬ УСТАНОВКИ Qt>/bin), но решение с обёртками мне кажется более логичным. К тому же не забывайте, что разработчик не ожидает такого поведения от вашей сборки Qt. Для компилятора отличного от MinGW решение с QMAKE_LFLAGS может быть единственным. Чтобы решить эту проблему для сборки на основе MinGW мы можем создать файлы-обёртки для линкера.

Итак, чтобы создать обёртку для библиотеки QtCore4.dll нужно:
  1. Создать пустой файл libQtCore4.a в подкаталоге lib;
  2. Добавить в него текст GROUP(../bin/QtCore4.dll). Этой строкой вы укажете линкеру, что ему нужно добавить в список линковки библиотеку QtCore4.dll из каталога bin.
Теперь когда ваш проект будет линковаться с QtCore4, линкер откроет файл lib\libQtCore4.a, прочтёт скрипт, и подлинкует библиотеку bin\QtCore4.dll. Повторите эти действия для всех библиотек из вашей сборки Qt (QtCore4.dll, QtGui4.dll, QtSql4.dll и т.д.). Теперь ваш инсталлятор cможет похудеть на 50-60 Mb, а установленная Qt - приблизительно на 500.

воскресенье, 27 октября 2013 г.

Перемещение собранного Qt4

Как известно, во время сборки Qt4 в библиотеке QtCore и qmake сохраняется путь к каталогу сборки, например F:\qt4. Если вы переместите этот каталог в другое место, например, F:\toolchains\qt4, и попытаетесь использовать его как новый профиль в Qt Creator, то некоторые вещи откажутся работать - например, не будет грузиться sqlite плагин, т.к. программа будет искать его по старому пути в F:\qt4. Для этих целей существуют специальные программы-патчеры, которые изменяют пути внутри QtCore или qmake. Рассмотрим следующие варианты:
  • QtBinPatcher. Источник: 1. Позволяет патчить все необходимые файлы без указания каких-либо параметров командной строки. Наилучший вариант из виденных мной;
  • QtPathCorrector. Источник: 1 2. Позволяет патчить файл без указания старого пути. Требует задать новый путь через параметры командной строки. Например, зайдите в перемещённый каталог F:\toolchains\qt4 и выполните: qtpathcorrector patch -n "%cd%" -f bin\qmake.exe bin\QtCore4.dll lib\QtCore4.dll . Пути в qmake и QtCore установятся в "F:\toolchains\qt4". Недостатки: если возникли ошибки, то файл, который должен был быть исправлен, становится размером 0;
  • QPatch. Источник: 1. Требует задать как старый, так и новый путь через параметры командной строки. Недостатки: нужно указывать старый каталог, новый путь должен быть короче старого (что скорее всего неприемлимо для вас);
Теперь qmake будет знать, что prefix поменялся, и будет использовать новое значение. Чтобы проверить установился ли новый prefix, выполните команду qmake -query.

Встречаются заметки, что нужно также патчить пути в .prl файлах в каталоге lib (т.е. F:\toolchains\qt4\lib), но я не обнаружил ошибок или неправильного поведения или компиляции своих программ, если эти пути оставить как есть при использовании патчера, которому нужно в явном виде указывать какие файлы патчить.

    вторник, 11 июня 2013 г.

    Использование ссылок svn+ssh:// на SourceForge

    Если вы используете svn репозиторий на sourceforge.net, TortoiseSVN на локальном компьютере, и репозиторий по протоколу svn+ssh://, то вы можете столкнуться с тем, что commit или checkout проваливается:

    svn: E720087: Can't create tunnel: Параметр задан неверно.

    Это связано с тем, что у вас в PATH отсутствует совместимая версия plink.exe. Чтобы исправить эту ситуацию, можно указать TortoiseSVN использовать свою собственную версию plink-a. Для этого создайте переменную окружения SVN_SSH с таким содержимым:

    C:/Program Files/TortoiseSVN/bin/TortoisePlink.exe

    Не забудьте указать правильный каталог, где установлен TortoiseSVN. Если же вы используете SSH ключи для авторизации, то эта переменная будет выглядеть так:

    "C:/Program Files/TortoiseSVN/bin/TortoisePlink.exe" -i ПУТЬ_К_PRIVATE_КЛЮЧУ
    Ссылки:

    понедельник, 10 июня 2013 г.

    Медленная инициализация SSL в Qt на Windows

    Если вы пишете сетевое приложение с помощью Qt и уже подложили SSL библиотеки в каталог с программой, и ваша программа успешно скачивает секретные данные по протоколу https, то вы могли заметить довольно медленную инициализацию приложения на Windows.

    Если раньше ваша программа стартовала и начинала скачивание данных по http за 200 мс., то теперь с https это время увеличилось до 800 мс. (и это на Phenom II X6)! Задержка происходит в методе QNetworkAccessManager::get(). Использовав профайлер AQTime я выяснил, что основная задержка была внутри модуля QtNetwork в функции q_RAND_status(). После гугления стало ясно, что SSL инфраструктуру в программе лучше инициализировать чем раньше тем лучше, и это связано с кучей (heap) приложения.

    Если ещё до создания объекта QApplication добавить следующий простой код, то инициализация программы сократится с 800 мс до 400 мс.:
    int main(int argc, char *argv[])
    {
        qDebug(QSslSocket::supportsSsl()
                   ? "SSL is supported"
                   : "SSL is not supported");
    
        QApplication app(argc, argv);
    
    ...
    Ссылки: