Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Базы";
Текущий архив: 2006.08.27;
Скачать: [xml.tar.bz2];

Вниз

Счетчик (?) в Firebird   Найти похожие ветки 

 
Urvin   (2006-06-15 18:23) [0]

Можно ли средствами сервера или запроса организовать следующую затею:

при добавлении данных в одну из таблиц (Insert Into Table1...) в одно из полей средствами сервера записывается его номер. При добавлении еще одной записи - новый номер, увеличенный на единицу.
После записи этого номера информация в ячейке не можжет изменяться, т.е. если из таблицы удаляется какая-то запись, то у последующих записей их номер не изменяется. и, например, в таблице содержатся записи #331, #332, #333. Удалим последнюю. Следующая добавленная запись будет иметь номер #334....

???


 
Ega23 ©   (2006-06-15 18:33) [1]

Обрати внимание на такую сущность, как генератор.


 
Desdechado ©   (2006-06-15 18:33) [2]

это называется генератор
в триггере перед вставкой пишешь
new.id=gen_id(genname, 1);


 
Urvin   (2006-06-15 18:43) [3]

тогда вопрос - при отключении/включении сервера значение обнуляется?
должен ли я каждый раз при обращении создавать триггер и генератор?


 
Desdechado ©   (2006-06-15 18:45) [4]

значение хранится в базе в системных таблицах
у тебя данные очищаются в твоих таблицах, когда сервер отключаешь?

про создание - один раз

а еще почитал бы ты ibase.ru что ли...


 
DSKalugin ©   (2006-06-15 18:46) [5]

читай о триггерах и генераторах
http://www.realcoding.net/article/view/1578


 
kaif ©   (2006-06-15 19:35) [6]

Только в триггер не суй, если хочешь вставлять данные вручную. Для запроса очередного значения генератора в IBX-компонентах есть специальное свойство Generator. Правда аиногда пдейт IBX нужно поставить, чтобы его увидеть. В этом свойстве указывается, какой генератор использовать при вставке новой записи, когда его запрашивать (OnPost) и в какому полу набора присваивать.
Если сделаешь в триггере - потом будешь мучиться с поиском только что добавленной записи (при Refersh датасета).
К тому же триггеры будут мешать при всяких закачках данных.
Кстати, значение генератора после таких закачек можно установить вручную:
SET GENERATOR <генератор> TO <значение>
И даже то ли в Firebird, то ли в Yaffil работала такая конструкция:
SET GENERATOR <генератор> TO SELECT MAX(<поле>) FROM <таблица>


 
Urvin   (2006-06-15 19:57) [7]

спасибо большое! разобрался!


 
Desdechado ©   (2006-06-15 20:40) [8]

kaif ©   (15.06.06 19:35) [6]
> в триггер не суй, если хочешь вставлять данные вручную
А вот это зря. Потому как в триггере всегда можно прописать
IF( new.id IS NULL ) THEN
new.id=gen_id(...);

А вот если без триггера, то ни одним скриптом нормально не вставишь данные.

> К тому же триггеры будут мешать при всяких закачках данных.
Проблемные триггеры при закачках можно отключать. Закачки ведь обычно явление редкое и не многопользовательское.


 
unknown ©   (2006-06-15 21:50) [9]


> kaif ©   (15.06.06 19:35) [6]
> Только в триггер не суй
...
> К тому же триггеры будут мешать при всяких закачках данных.

Какой бред...


 
Petr V. Abramov ©   (2006-06-15 23:36) [10]

идея с генераторм плоха, если "дырки" в номерах допустимы ТОЛЬКО при удалении.
 При откате транзакции (а это может случиться по сотне причин) значение генератора не откатывается.


 
Johnmen ©   (2006-06-15 23:42) [11]


> идея с генераторм...


А это не идея. Это стандартный механизм.
И если кто-то волнуется по поводу дырок, то он жуёт овощ не в том месте и не в то время...


 
DrPass ©   (2006-06-15 23:52) [12]

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


 
Petr V. Abramov ©   (2006-06-16 11:10) [13]

> Johnmen ©   (15.06.06 23:42) [11]
> А это не идея. Это стандартный механизм.
 Для генерации уникальных значений, и ни для чего другого. Можно, конечно, и не по назначению использовать, но кому-то и кобыла невеста


 
MsGuns ©   (2006-06-16 13:06) [14]

>kaif ©   (15.06.06 19:35) [6]
>Только в триггер не суй, если хочешь вставлять данные вручную.

?
Почитай Вострикова с Ковязиным хотя бы

>Для запроса очередного значения генератора в IBX-компонентах есть специальное свойство Generator. Правда аиногда пдейт IBX нужно поставить, чтобы его увидеть. В этом свойстве указывается, какой генератор использовать при вставке новой записи, когда его запрашивать (OnPost) и в какому полу набора присваивать.

Ашот, не надо всем ложащимся в постель советовать надевать презерватив.  Или хотя бы пиши, что это надо при правках через датасеты, а не явными запросами. Кроме того, неплохо бы еще учитывать особенности механизма транзакций, версионность и т.д.

>Если сделаешь в триггере - потом будешь мучиться с поиском только что добавленной записи (при Refersh датасета).

Вообще не понял. Что значит "мучиться с поиском", если получить новаое значение генератора перед вставкой вообще не представляет никакой проблемы. Хоть серез датасет, а хоть через отдельный запрос. И при чем тут Refresh ? Этот метод вовсе не заставляет датасет перечитать с сервера актуальные данные. Да и вообще я бы предостерег писателей "клиенских" приложений от использования этой чисто локальной фичи

>К тому же триггеры будут мешать при всяких закачках данных.

???
В [8] все написано. Хотя, конечно, если отказаться от использования генераторов в триггерах.. Типа нафига удочка, если я могу трусами рыбу ловить.

>Кстати, значение генератора после таких закачек можно установить вручную:
SET GENERATOR <генератор> TO <значение>
И даже то ли в Firebird, то ли в Yaffil работала такая конструкция:
SET GENERATOR <генератор> TO SELECT MAX(<поле>) FROM <таблица>

А это еще что за чудо-юдо рыба-кит ? Если, конечно, с БД работает строго один товарисч, то оно канешна..

Резюме, Ашот, ты ли это ?


 
kaif ©   (2006-06-16 15:32) [15]

2 MsGuns ©  
2 Desdechado ©   (15.06.06 20:40) [8]
А вот если без триггера, то ни одним скриптом нормально не вставишь данные.

 Возроажаю.
 При вставках явными запросами всегда можно написать (что я и делаю в таких ситуациях):

INSERT INTO AAA (ID, NAME) VALUES(GEN_ID(AAA_GEN,1), "Вася");

 Или вы никогда не использовали функцию GEN_ID() в текстах SQL-запросос INSERT?

 Тогда открою вам тайну.
 Такая контсрукция тоже работает:
 
 INSERT INTO AAA(ID, NAME)
 SELECT GEN_ID(AAA_GEN, 1), BBB.NAME FROM BBB

 Хотя возможно у Ковязина об этом ничего не сказано - не знаю. Я осваивал IB по Language Reference и американским авторам, а не по Ковязину.

Что значит "мучиться с поиском", если получить новое значение генератора перед вставкой вообще не представляет никакой проблемы.

Так вот если пользователь отказался от вставки (DataSet.Cancel), то генератор будет при таком подходе в любом случае щелкать. Я понимаю, что он резиновый. Но я нахожу это излишним действием, без которого вполне можно обойтись и делать запрос генератора на клиент непосредственно перед Post. ЧТО, СОБСТВЕННО, И ПОЗВОЛЯЮТ СДЕЛАТЬ IBX.

Странно, что все так ополчились.

Я отвечаю человеку, который еще не работал с генераторами.

Мне известно про отключение триггеров. И про отключение индексов и много еще про что известно.
Иногда я использую в триггерах контрукцию IF (NEW.ID IS NULL), так что о ней я тоже осведомлен.

У меня нет цели блистать знаниями в данном случае.

У меня была цель помочь человеку разобраться.

Так как действительно свойства Generator у IBDataSet той версии, что по умолчанию ставится в Delphi - нет.

И потому я нахожу, что сообщил ценную для автора вопроса информацию.
Кратчайший путь.

При закачках проблемы будут, если не отключить триггеры. А именно - ни чем не оправданное падение скорости вставки.
Хотя я готов взять аргумент о закачках обратно.
Дело здесь не в закачках, а ДУРНОЙ ТРАДИЦИИ, которую зачем-то создают такие, как Ковязин и многие другие уважаемые авторы.

В заключение скажу, что в триггерах я сам реализую обращения к генераторам крайне редко. Возможно большинство приложений, которые я пишу, в этом просто не нуждаются, хотя повсеместно и используют суррогатные ключи. А может быть все проще. Зачастую мне бывает нужно сообщение об ошибке, если я не указал поле ID при вставке. И я вовсе не желаю создавать себе косметический геморрой, вуалируя такие ошибки. Я человек крайне невнимательный. И если мне нужно было явно указать ID в инсерте, а я забыл это сделать в тексте запроса, то лучше я получу ошибку, чем "гладкий результат" типа "все в порядке". Но это уже моя личная манера программирования, которую я никому не навязываю. Если кто-то хочет избавитьсяот всех возможных ошибок априори - его право. Может даже перехватить Application.OnException и вписать туда exit.

 И вообще я вам скажу, что ничто так не сбивает с толку начинающего осваивать генераторы, как использование генератора в триггере. И именно из-за Refersh.

 Насчет Refresh скажу яснее. Если вы в IBDataSet вставите новую запись, которая получает значение ID из генератора в триггере, то запрос Refresh (который, кстати, IBDataSet выполняет автоматически после Post), не сможет найти вновь вставленную запись, если у вас отсутствует какой-нибудь альтернативный ключ.
 То есть грамотное решение для IBDataSet, который юзает таблицу с генератором в триггере должно выглядеть примерно так:

  SelectSQL.Text := "select id, name from aaa";
  ModifySQL.Text := "update aaa set name = :name where id = :id";
  DeleteSQL.Text := "delete dfom aaa where id = :id"l;
  RefresSQL.Text := "select id, name from aaa where name = :name";
 

  И при этом необходимо иметь UNIQUE (NAME) !!!!
  Или какое-нибудь иное уникальное поле, например, UNIQUE(CODE).
  Иначе Refresh просто не заработает.

 А если Refresh не заработает, то после Post датасет не сможет извлечь новое значение ID. А это чревато, например, тем, что если на клиенте имеется два датасета (Master и Detail), связанные через свойство DataSource, то при попытке вставить и послать запись из Detail датасета у того будет NULL в поле ссылки на главный датасет и возникнет ошибка внешнего ключа при верно организованной базе данных.
 
  И вместо того чтобы нападать на меня лично и советовать читать Ковязина пусть лучше мне покажут, как именно КЛИЕНТ узнает значение, только что присвоенное полю ID при INSERT, если таблица (а таких таблиц бывает очень много) устроена так:

  ID, NAME
 
  и в ней ID присваивается в триггере.
 
  Уникальный ключ на NAME не предлагать!

  Ответьте. И тогда я признаю, что kaif - дурак.


 
kaif ©   (2006-06-16 15:41) [16]

SET GENERATOR <генератор> TO SELECT MAX(<поле>) FROM <таблица>
А это еще что за чудо-юдо рыба-кит ? Если, конечно, с БД работает строго один товарисч, то оно канешна..


Да. Это именно когда работает один товарищ.
Который сделал Database Shutdown, закачал данные из какой-то другой базы, из которой ID брался явно, так как он перекачивал связанные талицы и не хотел геморроиться.
А затем установил значения генераторов туда, куда нужно.
И потом открыл общий доступ к базе.
Я не думал, что все надо разжевывать.
Просто сообщил информацию, что эта конструкция в одном из серверов работает (Yaffil иолиFirebird). В другом, кстати, на работает. А в каком именно работает - не помню, так как склероз. :)
Но попробовать ее рекомендую.
Может пригодится когда-нибудь при ручной работе.


 
Desdechado ©   (2006-06-16 16:12) [17]

kaif ©   (16.06.06 15:32) [15]
Зачем столько обиды-то?
Просто показали, что твой подход должен быть аргументирован (что ты и попытался сделать).

> Уникальный ключ на NAME не предлагать!
Я еще не встречал таблиц, в которых нет какой-либо уникальности и при этом которые заполняются вручную в сетке. Без уникальностей - это какие-то тупые протоколы/показания датчиков и т.п.
Остальные все равно имеют нечто (часто из нескольких полей) уникальное, по которым можно выудить и полученное от генератора значение поля.

Почему я использую подход с триггером - просто я не использую заточенные под IB компоненты. А в универсальных удобнее делать, как у людей, особенно в случае использования нескольких СУБД одновременно.

Скажу по секрету, Вострикова с Ковязиным не читал. Читал доки на инглише.


 
Desdechado ©   (2006-06-16 16:19) [18]

кстати, мастер-деталь тоже использую крайне редко, в основном для показа данных, а не редактирования

> INSERT INTO AAA (ID, NAME) VALUES(GEN_ID(AAA_GEN,1), "Вася");
Можно так, конечно. Но вижу сразу проблему. Например, у тебя есть скрипт из какой-то БД для массовой закачки. Ты будешь его модифицировать для использования генератора? Зачем? А триггер можно ли включить или нет, не трогая скрипт, а только зная, что он из себя представляет.
Да и для случаев ручного ввода данных минуя твою программу без генератора с триггером тяжко.

Все указанное не отметает твоих аргументов и подходов.
Но я не нахожу их настолько очевидными и хорошими, чтобы советовать новичкам. Тем паче, если они не знают тонкостей. Пусть лучше сами дойдут до каких-то решений, но только ПОСЛЕ того, как попробуют традиционный подход. Если захотят, конечно.


 
MsGuns ©   (2006-06-16 16:51) [19]

>kaif

Полностью согласен с Сашей (посты [17],[18]), в том числе и по поводу твоей, Ашот, обиды.

По поводу Ковязина. Я сам неоднократно критиковал его книги из-за явного и наглого :) лоббирования фибпласа. Однако про генераторы, триггера, транзакции и прочее у него написано очень неплохо.
То, что у тебя работает, есть частный случай, но не правило - и в этом вся причина наших возражений.
Я, к примеру, вообще стараюсь избегать "услуг" TIBDataSet в части редактирования, да еще и в связке Master-Detail. Хотя бы потому, что это усложняет мне явное управление транзакцией. И я не одинок.
Если уж приспичит юзеру править "как в экселе" (хотя это и дурная мода, т.к. дает иллюзию монопольного владения таблицей, что в принципе неверно), то я ему обеспечу и редактирование в гриде, и всякие чеки, выделения-перемещения, копирования и пр. другими способами, коих в дельфи можно нарыть без ограничений. Но привязывать технологию обмена данными с сервером к пользовательскому интерфейсу считаю в корне неверным подходом при разработке клиентских приложений.
Что же касается "заливок", о которых ты упоминал, то они делаются вовсе не датасетами, не генераторами и триггерами, а совсем иначе. О чем, кстати, тоже неплохо писано у Ковязина.
А наиболее верный подход - максимум выноса всей "правки" БД на сервер - в ХП, триггера и процедуры. Т.е. читаем датасетом, правим с помощью соотв.серверных средств. Потом перечитываем. Во всяком случае эта технология избавляет от гемора редактирования кода многочисленных "клиентов" при малейших изменениях в БД. Да и регулирует те же права на доступ к объектам БД.

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

Извини, если что..


 
kaif ©   (2006-06-16 17:04) [20]

2 Desdechado ©

Ладно, извини, погорячился.
Спасибо за спокойный ответ и за то, что удалось избежать перепалки. Я уже так привык к жестким перепалкам в "Прочем", что на все реагирую неправильно.

Я понял твой подход.
В принципе со многим согласен, кроме, пожалуй, того, что я чаще как раз склонен затачивать приложение под СУБД. ...Но это целый философский спор, причем, вечный (затачивать/не затачивать под СУБД) :)

Просто мне кажется, что новичка всегда вдохновляет то, что может сразу начать работать - с одной стороны, и прояснить механизм для понимания - с другой. Собственно, люди на форум и ходят для того, чтобы получить направление для быстрого понимания и решения своей проблемы. А фундаментальные сведения всегда можно почерпнуть из документации, книг или просто ища в поисковике статьи на какую-то тему.

Так как IBX-ы как бы всегда под рукой, я всегда советую новичку начать именно с их освоения. Они вовсе не так плохи - минимально наворочены, не используют БДЕ, хорошо совместимы по версиям.
Их исходный код позволяет многое понять и, что важно - он всегда под рукой...

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


 
kaif ©   (2006-06-16 17:25) [21]

2 MsGuns ©   (16.06.06 16:51) [19]
А разве я где-нибудь настаивал на каком-то правиле?
Наоборот, я как раз пытался устранить навязываемое правило: "обязательно обращаться к генератору в триггере BEFORE INSERT". Я нахожу это правило вредным. И не вижу иного происхождения для него, кроме как попытки универсализировать приложение под разные СУБД, имитируя поле типа "автоинкремент", которое IB не поддерживает.

Что касается Master-Detail в гридах, то я тоже так не делаю. Что не избавляет от необходимости все равно иметь ID, если нужно вводить Detail данные.

Возьму простой пример.
Создаем документ типа накладная. Имеется шапка и позиции. Я нахожу нормальным позиции вводить в гриде. Скажешь нет? Так вот после создания шапки (неважно как, пусть даже в отдельном модальном окне) потребуется, как ни крути, знать ID документа.
Сейчас мне скажут - запроси ID по уникальности дата+номер.
OK.
Но зачем?
Только потому что это "классика"?
А ничего, что я так и делал (запросы по альтернативным ключам) несколько лет подряд, пока тщетно пытался писать хорошие программы, нечувсвтительные к типу СУБД, пока не понял, что хорошую программу я так не напишу никогда. Так как это просто, видимо, не мой стиль. А как только я стал заниматься исключительно приложениями под заранее известную СУБД, вот тут я и обнаружил, что "классика" вовсе не так хороша, как кажется, и доставляет больше неудобств, нежели преимуществ.

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

Теперь докажите мне, что переделок в приложении будет меньше, чем в моем случае, когда я опирался только на ID при Refresh.

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


 
kaif ©   (2006-06-16 17:40) [22]

Я не считаю догмой даже такие священные понятия, как "бизнес-логика на сервере". Например, те же проверки диапазонов вводимых значений. Я практически никогда ими не пользуюсь. Скажете неправильно? А я вам скажу - я еще ни разу не слышал жалоб от юзеров на то, что компьютер не отловил ошибку диапазона. Возможно просто у меня юзеры никогда не вводят всякую ерунду без особых на то причин. И те случаи, когда особо оговаривалось, что нужны такие проверки, я их реализовывал не на сервере, а на клиенте. Так как эти диапазоны бывали весьма условны и юзерам нужно бывало их настраивать самостоятельно.

Единственные священные коровы, которые для меня остались от всей бизнес-логики на сервере, это: суррогатные ключи, правильные уникальности, NOT NULL и декларативная ссылочная целостность.
То есть все, что касается НОРМАЛИЗАЦИИ.
Все. Остальное все - не так важно.
ИМХО, конечно.
Что касается совращения новичков...
Кто и где запросит генератор... Какая на фиг разница?
О генераторах IB важно лишь знать один единственный существенный факт - генераторы IB работают вне контекста транзакций.
Все.
Все остальное в использовании генераторов - дело вкуса.


 
TohaNik ©   (2006-06-16 18:12) [23]


> kaif ©   (16.06.06 17:40) [22]
</I
> Я не считаю догмой даже такие священные понятия, как "бизнес-
> логика на сервере". Например, те же проверки диапазонов
> вводимых значений. Я практически никогда ими не пользуюсь.
>  Скажете неправильно? А я вам скажу - я еще ни разу не слышал
> жалоб от юзеров на то, что компьютер не отловил ошибку диапазона.
>  Возможно просто у меня юзеры никогда не вводят всякую ерунду
> без особых на то причин. И те случаи, когда особо оговаривалось,
>  что нужны такие проверки, я их реализовывал не на сервере,
>  а на клиенте. Так как эти диапазоны бывали весьма условны
> и юзерам нужно бывало их настраивать самостоятельно.

>
Ну чего ты разнервничался:)
Диапазоны в справочник констант, настраивай из приложения, проверяй на сервере.
Да у всех извилины по разному устроены, твой подход к неоторым вопросам оказался для многих нестандартным, а может и непонятным.

Ну MsGuns как всегда очень быстр на похвалы:)


 
kaif ©   (2006-06-16 21:35) [24]

2 TohaNik ©
Хорошо.
Если по-твоему я неспособен догадаться до таких вещей, как хранить настройки диапазонов в таблицах, которые может редактировать юзер, а проверять диапазоны в триггерах, то ты ошибся.
Так как не так давно я советовал здесь в Базах Данных одному товарищу именно так и поступить.

Здесь речь шла о диапазонах, проверяемых при помощи CHECK VALUES, то есть системными триггерами. И для редактирования этих настроек надо дать юзеру возможность изменять метаданные.
Если же ты не понял, то у нас с тобой действительно извилины по-разному устроены.

В общем. Думайте обо мне что хотите. Мне как-то совершенно по барабану. Я уже давно заметил. что основным мотивом участника этого форума вместо мысли "а почему бы не обсудить и такой вариант?" должна стать мысль "что обо мне будут думать?" и "как бы мне не уронить здесь свой жалкий авторитет?".

:(

Я не претендую здесь на звание мастера, так что все ревнители правильных подходов могут спать спокойно.

 Я просто играю в игру "я всего лишь пытался вам помочь". Есть такая игра для невротиков.
 Иногда мне бывают благодарны участники.
 И этот результат для меня больше значит, чем какие угодно мнения мэтров.
 Так как я сам частенько получал здесь неоценимую помощь.
 И уверяю вас, у меня никогда не было проблем, связанных с тем, что меня, как новичка направили "куда-то не туда". Потому что я всегда полагал, что когда я использую чей-то совет, то прежде всего важно чтобы у меня были мозги, а не у советующего. Так как советующий советует, а пишущий пишет. И здесь - терпение пророков.
 Я не боюсь пойти по ложному пути.
 И поэтому не боюсь направить кого-то другого по ложному пути.
 Так как у каждого - свой путь.


 
Андрей Пазик   (2006-06-18 22:57) [25]

юзай insert returning, в триггере дергай генератор.
Начиная с FB 2.0


 
DrPass ©   (2006-06-19 02:13) [26]


> Андрей Пазик   (18.06.06 22:57) [25]

Релиза FB2.0 еще не существует. А следовательно, юзать ее не нужно


 
Desdechado ©   (2006-06-19 13:28) [27]

> основным мотивом участника этого форума...
И снова обиды. Зря. На обиженных воду возят. Пост [22] стал бы хорошим завершением, с грамотной аргументацией. А [24], имхо, перевел все в личную плоскость, что у новичков вполне может отбить желание вообще что-то из всей этой дискуссии использовать.

> Так как у каждого - свой путь.
Вспомнилось:
"Каждый идет к истине своим путем. А на перекрестке сижу я, Будда..."


 
kaif ©   (2006-06-19 18:50) [28]

2 Desdechado ©  
Ты прав.



Страницы: 1 вся ветка

Форум: "Базы";
Текущий архив: 2006.08.27;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.58 MB
Время: 0.051 c
1-1152768680
ORMADA
2006-07-13 09:31
2006.08.27
Сихронизация видимого в ListBox и CheckListBox


15-1153933684
TStas
2006-07-26 21:08
2006.08.27
Как лучше всего защитить прогу, если она не предназначена для про


15-1153954538
SergProger
2006-07-27 02:55
2006.08.27
Программа DelphiWorld


2-1155087755
vladimirg88
2006-08-09 05:42
2006.08.27
Форма


3-1150225565
molodoi
2006-06-13 23:06
2006.08.27
Фильтр по индексным полям





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский