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

Вниз

Динамическое создание строк   Найти похожие ветки 

 
Skier   (2002-06-26 13:18) [0]

Господа, мне нужно динамически создавать строки
(не PChar, а именно String(!) )

Я делаю что-то вроде этого :

.......................
type
PString = ^String;
var
AStr := AllocMem(4);
AStr^ := "hello, world !"
FreeMem(AStr, 4);
.......................

Вроде бы всё работает, но что-то меня
терзают смутные сомненния : не происходит ли memory leak ?
И вообще как это всё лучше всего делать ?


 
Kaban   (2002-06-26 13:26) [1]

че-то я не вижу где тут "динамически создаются строки"
и что вы вообще под этим подразумеваете


 
Anatoly Podgoretsky   (2002-06-26 13:27) [2]

Зачем такое извращение, работа со строками и так происходит динамически и автоматически.


 
Игорь Шевченко   (2002-06-26 13:29) [3]

А зачем? Строка же так создается динамически и, по сути, является указателем


 
Skier   (2002-06-26 13:29) [4]

> Kaban

Ну да... не строка создаётся, а указатель на неё родимую.
Но всё равно вроде работает, а вроде бы что-то тут не так...


 
panov   (2002-06-26 13:31) [5]

str := "hello, world !";
...
str := ""; //память освобождена


 
Skier   (2002-06-26 13:33) [6]

> Игорь Шевченко
> Anatoly Podgoretsky

Мне нужно программно создать указатель на строку и работать
с ней, а потом этот указатель прибить.
Но меня интересует убъётся ли строка hello, world ! ?
(в моём случае) станет ли кол-во сслылок на неё = 0, чтобы
Delphi снесла её из памяти ??


 
Kaban   (2002-06-26 13:34) [7]

По моему это уж лишнее
str := ""; //память освобождена


 
Kaban   (2002-06-26 13:36) [8]

Бред


 
panov   (2002-06-26 13:36) [9]

>Kaban © (26.06.02 13:34)
По моему это уж лишнее
В общем случае - нет. -)
Например, для глобальных переменных...


 
panov   (2002-06-26 13:37) [10]

>Skier © (26.06.02 13:18)
FreeMem освобождает память. В чем проблема-то?


 
Игорь Шевченко   (2002-06-26 13:42) [11]

Skier © (26.06.02 13:33)

Не можете привести пример, а то непонятно...

По-моему, проще не мучиться со строками, а выделить память под текст, иметь на него указатель типа PChar...


 
Skier   (2002-06-26 13:44) [12]

> panov

Проблема в следующем : будет ли освобождаться
память выделенная Delphi под "hello, world !" ?
Меня это очень интересует.


 
:smile:   (2002-06-26 13:49) [13]

Не будет. Освободится только 4 байта указателя.


 
Skier   (2002-06-26 13:49) [14]

> Игорь Шевченко
Код я весь привёл.
Мне нужен именно String (см. Вопрос)

будет ли освобождаться память выделенная Delphi под "hello, world !" ?
Т.е. будет ли обнуляться счётчик ссылок на "hello, world !" ?


 
Kaban   (2002-06-26 13:51) [15]

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


 
Skier   (2002-06-26 13:52) [16]

> :smile:
"Не будет" - это не ответ.
Нужны доказательства !


 
Skier   (2002-06-26 13:55) [17]

> Kaban
ОГРОМНОЕ СПАСИБО !
Я никак не мог догадаться :)


 
Kaban   (2002-06-26 14:00) [18]

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


 
panov   (2002-06-26 14:01) [19]

будет ли освобождаться память выделенная Delphi под "hello, world !" ?

Да. Странно было бы, если бы память не освобождалась.
String/AnsiString стандартный тип в паскале и Delphi прекрасно умеет с ним работать.

При выполнении оператора присваивания
AStr^ := "hello, world !";
память динамически перераспределяется и
FreeMem(AStr) будет освобождать не 4 байта памяти, а именно столько, сколько выделено под "hello, world !".

Т.е. будет ли обнуляться счётчик ссылок на "hello, world !" ?
Непонятно, о чем речь.


 
Viewer   (2002-06-26 14:02) [20]

Ну так и докажи себе сам.
В цикле набери длину строки на 1Мег
s := s + "1234567890";
Посмотри на MemAvailable
Затем s := "";
И опять посмотри.


 
:smile:   (2002-06-26 14:03) [21]

>Skier © (26.06.02 13:52)
>"Не будет" - это не ответ.
"Не будет" - это как раз ответ. На вопрос "будет ли..."

Просьбы о доказательствах я не видел.
Вообще-то это очевидная вещь.


 
VDen   (2002-06-26 14:04) [22]

Per rectum ad astera :))


 
Skier   (2002-06-26 14:05) [23]

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


 
Skier   (2002-06-26 14:10) [24]

> panov
"Непонятно, о чем речь"
Речь о том что "в строке" (когда память под
неё выделяет Delphi) храниться её длина и количество ссылок
на неё, так вот если на строку больше никто не ссылается то она
сносится из памяти. Отсюда и мой вопрос.
И мне очень бы хотелось получить на него доказательный ответ.
Ну очень нужно !


 
Skier   (2002-06-26 14:12) [25]

> VDen
Да, да именно к звёздам !
А конкретно что-нибудь можешь сообщить ?


 
panov   (2002-06-26 14:12) [26]

так вот если на строку больше никто не ссылается то она
сносится из памяти.

Почему это она сносится из памяти?

Раз ты динамически создаешь переменную типа String, то пока ты ее принудительно не освободишь FreeMem, никуда память не освободится, и ссылки тут ни при чем.


 
Kaban   (2002-06-26 14:14) [27]

>Речь о том что "в строке" (когда память под
>неё выделяет Delphi) храниться её длина и количество ссылок
>на неё, так вот если на строку больше никто не ссылается то она
>сносится из памяти.
Че то я в этом сильно сомневаюсь


 
VDen   (2002-06-26 14:15) [28]

2Skier © (26.06.02 14:12)
Вообще-то вы меня неправильно поняли. "Per rectum" - термин медицинский, означает "через задний проход". Можно сделать проще...


 
Skier   (2002-06-26 14:16) [29]

> panov
"ссылки тут ни при чем"
Как ты не прав !
Я динамически создаю указатель на строку и потом
"говорю" Delphi разместить там ссылку на "hello, world !".

А FreeMem освобождает только указатель. или нет ?


 
Anatoly Podgoretsky   (2002-06-26 14:19) [30]

panov © (26.06.02 14:01)
Шире, ключевое слово, часть языка, в отличии от других типов


 
McSimm   (2002-06-26 14:20) [31]

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

Освобождения памяти от строки не произойдет.
Какие доказательства тут можно привести? Могу предложить посмотреть ассемблерный код, сгенерированный компилятором.

>если на строку больше никто не ссылается
Этот аргумент здесь не подходит. "AStr^ := " не увеличивает ref.count строки. И тут все зависит от того способа каким это строка создана.


 
Skier   (2002-06-26 14:27) [32]

> McSimm
Мне кажеться, что AStr^ := "hello, world !"
создаёт строку "hello, world !" в памяти, вот
если написать так :

AStr^ := "hello, world !";
а потом
AStr^ := "";
(далее всё по тексту)

То в этом случае memory leak не будет точно или я не прав ?





 
panov   (2002-06-26 14:33) [33]

>McSimm © (26.06.02 14:20)
Освобождения памяти от строки не произойдет
Почему? см. panov © (26.06.02 14:01)


 
valery_f   (2002-06-26 14:35) [34]

Насколько я помню, переменная типа string - это указатель на выделенную память. От этого адреса в "плюс" идет строка с нулем в конце (т.е. переменную можно использовать как PChar), а в обратную - служебная информация, включая длину строки и пр. (состав и формат служ. информации зависит от версии). Видимо там же расположен и счетчик ссылок.

Что касается освобождения памяти, то этим занимается дельфийский "сборщик мусора", т.е. s:="" память, скорее всего, мгновенно не освободит. Однако заморачиваться по этому поводу не стОит, т.к. этих "сборщиков" - целая куча и в винде (к примеру - высвобождение хэндлов после обнуления счетчика ссылок на них), и в дельфи (строки, COM-объекты и пр.) и всё пока что работает. Во всяком случае, по результатам тестов дельфи делает VB, C#, VC++ и Intel C++ по скорости и качеству работы с памятью.


 
McSimm   (2002-06-26 14:40) [35]

Все немножко (самую малость) сложнее. Попробую объяснить.
Как я уже написал,
> тут все зависит от того способа каким это строка создана


Для начала необходимо понять, что FreeMem и освобождение памяти от строки - не связаны. Т.е. могут быть случаи, когда строка будет освобождена даже если вы не освобождаете AStr. И наоборот.

AStr - указатель на выделенный блок памяти 4 байта.
В этих четырех байтах хранится указатель на строку.

Конкретно в приведенном примере AStr^ := "hello, world !"
вообще не будет выделяться память под строку - она уже есть в сегменте данных и AStr^ просто получит на нее указатель.

В другом случае, напр. AStr^ := IntToStr(12345) будет создана строка "12345" динамически, но счетчик испоьзования увеличен не будет, сколько указателей на нее бы не ссылались. Строка будет уничтожена компилятором при выходе из процедуры, не зависимо от того освободите ли вы память от указателей или нет.


 
Viewer   (2002-06-26 14:42) [36]

Я уже предложил вопрошающему проверку.
Viewer (26.06.02 14:02)

При s:="" память очень даже освобождается и в Win98

>valery_f (26.06.02 14:35)
>Во всяком случае, по результатам тестов дельфи делает VB, C#, >VC++ и Intel C++ по скорости

Вот здесь не надо ля-ля. На строках именно паскаль и тормозит.


 
Skier   (2002-06-26 14:53) [37]

> McSimm
Т.е. код ошибочен, даже если
писать

AStr^ := "hello, world !";
AStr^ := "";

??????


 
McSimm   (2002-06-26 15:04) [38]

Смотря как посмотреть :)

Собственно ошибки тут нет.
AStr^ := ""; - корректно освободит память от строки
FreeMem - освободит память от указателя



 
Skier   (2002-06-26 15:11) [39]

> McSimm
А всё-таки ?

А если это будет не строка а скажем Varinant и
будет использоваться соотв-но
PVariant = ^Varinant, будет тоже самое или как ??
(Имею в виду memory leak)



 
McSimm   (2002-06-26 15:12) [40]

Чтобы понятнее было почему компилятор не должен освобождать строку, можно проделать такой опыт:

AStr := AllocMem(4);
// AStr^ := "hello, world !";
Pointer(AStr^) := Pointer(123456); // произвольные 4 байта
FreeMem(AStr, 4);

Ошибки нет. Все будет работать. Только потому, что программа не будет пытаться освободить строку по отфонарному адресу


 
Skier   (2002-06-26 15:19) [41]

>McSimm
Это понятно.
Когда я писал "код ошибочен"
я имел в виду не будет ли утечки памяти.

Т.е. меня очень интересовала "внутреняя работа Delphi со
строками". (выделение памяти, подсчёт ссылок и освобождение памяти).


 
McSimm   (2002-06-26 15:30) [42]

Тут достаточно понять такую штуку.

FreeMem( указатель) освобождает выделенные 4 байта памяти в куче.
На что указывал этот указатель и были ли эти 4 байта указателем вообще - процедуре FreeMem безразлично.

Соответственно то что скрывается за указатель^ становится сиротой, если только нет других на это ссылок.

Вот пример.

S := DateToStr(Now);
AStr := @S;
FreeMem(AStr);

строка с датой проживет ровно столько, сколько проживет переменная S. И FreeMem не помешает.

Если же то же самое без переменной S - то строка будет имеет статус локальной переменной с минимальным сроком жизни. И опять же никак не зависит от FreeMem.


 
Игорь Шевченко   (2002-06-26 15:32) [43]

Если имеется локальная(ые) переменная типа String
то генерируется код:
begin
try
... тело процедуры
finally
_LStrClr(локальнаяпеременнаяString);
end;
end; { Процедуры }


 
Skier   (2002-06-26 15:39) [44]

> McSimm
Т.е. на сколько я понял подсчёт ссылок ведётся только
тогда когда строка создаётся самой Delphi

var
AStr : String;
//и т.д.

Или можно как-то ещё заставить Delphi считать ссылки ?

"FreeMem(указатель) освобождает выделенные 4 байта памяти в куче."

Мне кажеться что это не так, допустим :

type
TMyRec = packed record
mrField1 : Integer;
mrField1 : Integer;
end;
PMyRec = ^TMyRec
var
AMyRec : PMyRec;
begin
AMyRec := AllocMem(SizeOf(TMyRec));
//работа с AMyRec
FreeMem(AMyRec);
//сколько FreeMem освободит? 4 или SizeOf(TMyRec) байт ??
end;




 
Skier   (2002-06-26 15:41) [45]

> Игорь Шевченко
Это как раз понятно.


 
McSimm   (2002-06-26 15:50) [46]

сколько FreeMem освободит? 4 или SizeOf(TMyRec) байт ??
Разумеется SizeOf(TMyRec).

Кстати, обратите внимание, Если элементом TMyRec будет строка, то FreeMem(AMyRec) не освободит память от строки! только от AMyRec


 
valery_f   (2002-06-26 15:55) [47]

> McSimm © (26.06.02 15:30)
> FreeMem(указатель) освобождает выделенные 4 байта памяти

Ты хоть сам-то понял что сказал? Освобождается память !по адресу! записанному в указателе, а сам указатель (размером 4 байта) от этого никак не меняется.

> На что указывал этот указатель и были ли эти 4 байта указателем вообще - процедуре FreeMem безразлично.

Как это безразлично? Все выделенные куски памяти значатся в таблице, именно поэтому FreeMem не требует указания размера освобождаемой памяти - оно известно. Попробуй сделать FreeMem левого указателя - не знаю что там у тебя, а у меня Access violation...


 
Skier   (2002-06-26 15:58) [48]

>McSimm
А если для освобождения строки использовать
Finalize ?

Т.е.


type
TMyRec = String;
PMyRec = ^TMyRec;
var
AMyRec : PMyRec;
begin
AMyRec := AllocMem(SizeOf(TMyRec));
AMyRec^ := "hello, world !";
Finalize(AMyRec^);
FreeMem(AMyRec, SizeOf(TMyRec));
end;

?????????


 
Толик   (2002-06-26 16:04) [49]

Прошу прощения, что вмешиваюсь в столь активную беседу (очень уж интересная получается!) и посмею высказать своё мнение. Раз уж нужно формировать строки динамически, то может быть всё-таки использовать указатель на массив символов, а потом, в нужных местах заниматься приведением к типу string? Так ведь проще... Насчёт счётчика ссылок в строках - он есть только в ansistring а в string есть только размер и сами символы (если я конечно ничего не путаю). Так что моё мнение - использовать pchar + приведение типов (оно ведь память не выделяет, по крайней мере не должно).


 
Skier   (2002-06-26 16:09) [50]

> Толик

"Насчёт счётчик а ссылок в строках - он есть только в
ansistring а в string есть только размер и сами символы (если я конечно ничего не путаю)"

IMHO,путаешь.
У Марко Канту в книжке был пример про кол-во ссылок к строке.


 
McSimm   (2002-06-26 16:10) [51]

>valery_f (26.06.02 15:55)
Тут маленькое недоразумение. (Тов. Фарфуркис - устраните :)

FreeMem( указатель) освобождает выделенные 4 байта памяти потому что указатель был получен как AllocMem(4); Именно эти 4 байта (а не 4 байта указателя) и будут возвращены куче. А что в этих 4х байтах хранилось - неважно.

Так понятнее?

>А если для освобождения строки использовать
>Finalize ?
Можно. А можно использовать New-Dispose - в этой связке Finalize уже есть


 
valery_f   (2002-06-26 16:12) [52]

Только что глянул в отладчике - при выходе из процедуры локальная строка уничтожается через LStrClr. На входе у LStrClr - строка, т.е. указатель. Грубо говоря, LStrClr вычитает из этого адреса восемь байт (судя по всему - размер служебной информации) и уже для этого адреса зовет FreeMem. Так что звать FreeMem для самой строки (т.е. исходного указателя) - дохлый номер (в смысле - Access violation :)

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


 
Kaban   (2002-06-26 16:13) [53]

2McSimm
>(Тов. Фарфуркис - устраните :)

а ник у тебя часом не оттуда же :-)


 
Skier   (2002-06-26 16:14) [54]

> McSimm
В последнем куске кода будет memory leak как считаешь ?
Или это те же груши только в профиль :)


 
McSimm   (2002-06-26 16:16) [55]

>Skier © (26.06.02 13:18)
Прошу понять меня правильно.
Мои высказывания носили теоретический характер, не привязанно к данной конкретной задаче. Т.е. вопрос интересен в смысле понимания внутренних механизмов работы.

Раз речь зашла о том как же лучше сделать - мой совет, использовать TStringList.
Либо PChar с приведением типов, как посоветовал Толик.

Кстати, Толик, - счетчик у строк есть.


 
Skier   (2002-06-26 16:18) [56]

> valery_f
Ну так как насчёт memory leak ?


 
Skier   (2002-06-26 16:23) [57]

>McSimm
Буду очень признателен если расскажешь
про свой подход через TStringList.
Для варианта с использованием :
1) PString = ^String
2) PVariant = ^Varinant


 
McSimm   (2002-06-26 16:25) [58]

>Skier © (26.06.02 16:18

Из вышесказанного следует, что тебя должны беспокоить две проблемы.
1. Будет ли утечка памяти
2. Проживет ли строка так долго как мне этого хотелось бы.

Ты совсем упускаешь из виду вторую проблему. Как я уже говорил легко написать такой код, когда строка будет уничтожаться менеджером строк OP не тогда когда этого хочется и ссылки AStr будут хранить указатели на свободную (или перераспределенную) память.

Поэтому лучше изменить подход. Или добиться полного взаимопонимания с диспетчером строк OP.


 
Skier   (2002-06-26 16:29) [59]

>McSimm

1) ОР - это чаво ?
2) Про TStringList расскажешь ?


 
McSimm   (2002-06-26 16:37) [60]

>Skier © (26.06.02 13:18)
OP - Object Pascal. Лень набирать было :)

Вариантов много. Для строк удобно использовать TStringList. Для общего случая можно использовать record и/или TList. Можно использовать динамические массивы.
Опять же, заменив AllocMem-FreeMem на New-Dispose можно решить проблему с минимальными затратами.

Что рассказать про TStringList? Это удобный класс для массивов строк.


 
Skier   (2002-06-26 16:41) [61]

>McSimm
"Это удобный класс для массивов строк."
Я это давно заметил :))
Ну в общем, ладно, я понял что в моём коде память течёт-таки.
Буду искать другие подходы.




 
McSimm   (2002-06-26 16:45) [62]

>Буду искать другие подходы.

var
AStr: PString;
AVar: PVariant;
AAnyRec: PMyRec;
begin
New(AStr) ; // (AVar, AAnyRec)
AStr^ := ... // (AVar, AAnyRec)
...
Dispose(AStr); // (AVar, AAnyRec)


 
McSimm   (2002-06-26 16:46) [63]

>Kaban © (26.06.02 16:13)
> а ник у тебя часом не оттуда же :-)

Вообще-то нет.
Не припомню, а что там такое было?


 
Толик   (2002-06-26 16:51) [64]

насчёт счётчика ссылок в строках:
читаем делфёвые хелпы:

1. String types:

In the default {$H+} state, the compiler interprets string (when it appears without a bracketed number after it) as AnsiString. Use the {$H–} directive to turn string into ShortString.

т.е. по умолчанию string это не string а ansistring.

2. Short strings:

A ShortString is 0 to 255 characters long. While the length of a ShortString can change dynamically, its memory is a statically allocated 256 bytes; the first byte stores the length of the string, and the remaining 255 bytes are available for characters.

так что нету счётчика ссылок у стандартного string"а, только если ansistring...


 
Skier   (2002-06-26 16:54) [65]

> McSimm
New(AStr) динамически создаёт строку и в этом случае
память не будет утекать ? Ты уверен ??

>Толик
Похоже на правду...


 
McSimm   (2002-06-26 16:55) [66]

2Толик
Зависит от того что считать стандартным string"ом ShortString или AnsiString. :)

Я привык считать стандартным AnsiString. Т.к. считаю что ShortString оставлен только для совместивмости.

В любом случае из обсуждения легко понять что речь идет именно об AnsiString


 
McSimm   (2002-06-26 17:15) [67]

и в этом случае
память не будет утекать ? Ты уверен ??


- Если каждому New будет соответствовать Dispose,
- Если в создаваемой record не будет новых заморочек с указателями (типа record A: Integer; P: PString end)
- Если не будет ошибок
То память исчезать не будет. Уверен.

PS
Хотя я, как и любой человек, могу быть уверенным в неправильных вещах и нет информации ценнее собственного опыта :)


 
Skier   (2002-06-26 17:25) [68]

>McSimm
Извини, что достаю, но всё-таки хочется до конца
разобраться.

А чем в моём случае отличаются New от GetMem(4) ?
Т.е. почему код не работает если использовать GetMem ??


 
McSimm   (2002-06-26 18:11) [69]

Я не говорил что не работает. Можно GetMem-FreeMem использовать, но с принудительной очисткой строки либо присвоением "", любо вызовом finalize.

Вариант с New-Dispose я привел как универсальный способ для хранения различных типов данных (строки, варианты и пр.)
Dispose освобождением этих типов сам озабочен :)
и не надо будет об этом заботиться :
---
For global variables, local variables, objects, and dynamic variables deallocated using Dispose, the compiler generates code that finalizes all long strings, variants, and interfaces contained by the variable when the instance is destroyed.
---


 
valery_f   (2002-06-26 18:27) [70]

Народ, похоже мы слишком далеко уехали... В исходном примере динамически создается указатель на указатель (!), и к динамическому созданию строк это отношения вообще никакого не имеет. Это больше напоминает проверку на сообразительность компилятора - догадается ли он, что на ту строку кто-то косвенно ссылается или нет.

Я бы предложил попробовать уточнить исходную постановку задачи и разобраться - стОит ли лезть в эти дебри и изобретать велосипед, путаясь в том - строку ли мы уничтожаем, указатель на нее или указатель на указатель на нее... :)


 
Skier   (2002-06-26 18:45) [71]

>valery_f
"...на сообразительность компилятора"
Да ! Именно в этом я и хотел разобраться (см.
Skier © (26.06.02 15:19) )


 
Kaban   (2002-06-27 11:02) [72]

2 McSimm
"Обитаемый остров" читал


 
McSimm   (2002-06-27 12:38) [73]

>Kaban © (27.06.02 11:02)
Понятно.
Нет, ножик я не ел :)



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

Форум: "Основная";
Текущий архив: 2002.07.15;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.63 MB
Время: 0.014 c
3-47077
shiva502
2002-06-21 02:58
2002.07.15
Жутко тупит DataSet на широких таблицах


7-47815
aleksander
2002-04-18 17:25
2002.07.15
Блокировка клавиатуры из сервиса


6-47629
Jeck
2002-04-30 10:58
2002.07.15
Delphi -> С


14-47761
Gu
2002-06-11 18:03
2002.07.15
Разгон монитора с 15 до 17


14-47773
Erlan
2002-06-13 09:33
2002.07.15
Беда просто.





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский