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

Вниз

Динамический массив структур (record) как свойство класса.   Найти похожие ветки 

 
SingleStranger   (2009-02-11 13:19) [0]

Как реализовать?
Меня интересует способ с простым доступом к любому полю структуры.
Что-то типа того:
TRec = record
 field1: integer;
 field2: string;
end;

TSomeClass = class
 private
   FSRec: array of TRec;
   function GetSRec(Index: Integer): TRec;
   procedure SetSRec(Index: Integer; const Value: TRec);
 public
   function SRecAddNew: Integer;
   function SRecAdd(Value: TRec): Integer;
   property SRec[Index: Integer]: TRec read GetSRec write SetSRec;
end;

И доступ, чтобы был простым, примерно так:
var
 i: integer;
 r: TRec;
begin
 r.field1 := 1;
 r.field2 := "aaa";
 i := SomeClass.SRecAdd(r);
 SomeClass.SRec[i].field2 := "bbb";
end;

или как-то так:
var
 i: integer;
begin
 i := SomeClass.SRecAddNew();
 SomeClass.SRec[i].field2 := "bbb";
end;


 
clickmaker ©   (2009-02-11 13:39) [1]

и в чем проблема?


 
SingleStranger   (2009-02-11 13:43) [2]


> clickmaker ©   (11.02.09 13:39) [1]
> и в чем проблема?

Помоему, "Left side cannot be assigned to", если не ошибаюсь. Я код-то переписал, но нынешний вариант, вообще не устраивает. Вот и решил спросить.


 
Ega23 ©   (2009-02-11 13:44) [3]


TSomeClass = class
private
  FSRec: array of TRec;
  function GetSRec(Index: Integer): TRec;
  procedure SetSRec(Index: Integer; const Value: TRec);
public
  function SRecAdd(Value: TRec): Integer;
  property SRec[Index: Integer]: TRec read GetSRec write SetSRec;
end;

function TSomeClass.GetSRec(Index: Integer): TRec;
begin
 Result := FSRec[Index];
end;

procedure TSomeClass.SetSRec(Index: Integer; const Value: TRec);
begin
 FSRec[Index].field1 := Value.field1;
 FSRec[Index].field2 := Value.field2;
end;

function TSomeClass.SRecAdd(Value: TRec): Integer;
begin
 SetLength(FSRec, Hight(FSRec) + 1);
 SetSRec(Hight(FSRec), Value);
 Result := Hight(FSRec);
end;


Что-то типа этого.
P.S. С динамическими массивами практически не работал, поэтому не уверен, как правильно отработает
procedure TSomeClass.SetSRec(Index: Integer; const Value: TRec);
begin
 FSRec[Index].field1 := Value.field1;
 FSRec[Index].field2 := Value.field2;
end;

Возможно достаточно FSRec[Index] := Value;
Надо проверять.


 
SingleStranger   (2009-02-11 13:46) [4]


> SingleStranger   (11.02.09 13:43) [2]
> Помоему, "Left side cannot be assigned to"

При доступе к полю структуры.


 
Anatoly Podgoretsky ©   (2009-02-11 13:48) [5]

> SingleStranger  (11.02.2009 13:19:00)  [0]

У тебя нет свойства SomeClass.SRec[i].field2
Или делай свойство или копируй во временную переменную.


 
Ega23 ©   (2009-02-11 13:55) [6]

Если честно, то я бы TRec сделал классом, а в TSomeClass либо TObjectList в привате организовал с методами доступа, либо сам TSomeClass от TObjectList унаследовал (это уже от логики зависит).


 
SingleStranger   (2009-02-11 13:55) [7]


> Anatoly Podgoretsky ©   (11.02.09 13:48) [5]
> > SingleStranger  (11.02.2009 13:19:00)  [0]У тебя нет свойства
> SomeClass.SRec[i].field2Или делай свойство или копируй во
> временную переменную.

Т.е.?
var
i: integer;
r: TRec;
begin
 i := 0;
 r := SomeClass.SRec[i];
 r.field2 := "bbb";
 SomeClass.SRec[i] := r;
end;

Так? Это еже неудобно.

А проще не получится?


 
SingleStranger   (2009-02-11 13:55) [8]


> Anatoly Podgoretsky ©   (11.02.09 13:48) [5]
> > SingleStranger  (11.02.2009 13:19:00)  [0]У тебя нет свойства
> SomeClass.SRec[i].field2Или делай свойство или копируй во
> временную переменную.

Т.е.?
var
i: integer;
r: TRec;
begin
 i := 0;
 r := SomeClass.SRec[i];
 r.field2 := "bbb";
 SomeClass.SRec[i] := r;
end;

Так? Это еже неудобно.

А проще не получится?


 
Anatoly Podgoretsky ©   (2009-02-11 14:00) [9]

> SingleStranger  (11.02.2009 13:55:07)  [7]

Тебе привели два решения, а ты губы морщишь.
Не нравится предложеные, тогда сделай функции присвоения и вызывай их.


 
Anatoly Podgoretsky ©   (2009-02-11 14:01) [10]

> SingleStranger  (11.02.2009 13:55:08)  [8]

Проще вариант со свойствами.


 
SingleStranger   (2009-02-11 14:10) [11]


> Anatoly Podgoretsky ©   (11.02.09 14:01) [10]
> Проще вариант со свойствами.

Это как? Массив свойств?

> Anatoly Podgoretsky ©   (11.02.09 14:00) [9]
> тогда сделай функции присвоения и вызывай их.

Если это единственный способ, то видимо придется. Хотя, если честно, мне он не нравится.

> Ega23 ©   (11.02.09 13:55) [6]
> ... я бы TRec сделал классом, а в TSomeClass
> либо TObjectList в привате организовал с методами доступа ...

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

Есть еще варианты?


 
Ega23 ©   (2009-02-11 14:20) [12]


> А проще не получится?


Вот проще (сугубо ИМХО):

unit Unit2;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs, Contnrs;

type

 TSomeClass = class (TObject)
 private
  FField1 : Integer;
   FField2: string;
 public
  procedure Assign(source : TSomeClass);
  property Field1 : Integer read FField1 write FField1;
  property Field2 : string read FField2 write FField2;
 end;

TSomeClassContainer = class (TObject)
 private
   FItems : TObjectList;
   function GetCount: Integer;
   function GetItem(Index: Integer): TSomeClass;
   procedure SetItem(Index: Integer; const Value: TSomeClass);
 public
   constructor Create;
   destructor Destroy; override;

   function AddItem(Item : TSomeClass) : Integer;
   procedure DeleteItem(Index : Integer);
   procedure Clear;

   property Items[Index : Integer] : TSomeClass read GetItem write SetItem;
   property Count : Integer read GetCount;

 end;

implementation

{ TSomeClass }

procedure TSomeClass.Assign(source: TSomeClass);
begin
 FField1 := source.FField1;
 FField2 := source.FField2;
end;

{ TSomeClassContainer }

function TSomeClassContainer.AddItem(Item: TSomeClass): Integer;
begin
 Result := FItems.Add(Item);
end;

procedure TSomeClassContainer.Clear;
begin
 FItems.Clear;
end;

constructor TSomeClassContainer.Create;
begin
 FItems := TObjectList.Create(True);
end;

procedure TSomeClassContainer.DeleteItem(Index: Integer);
begin
 FItems.Delete(Index);
end;

destructor TSomeClassContainer.Destroy;
begin
 FItems.Free;
 inherited;
end;

function TSomeClassContainer.GetCount: Integer;
begin
 Result := FItems.Count;
end;

function TSomeClassContainer.GetItem(Index: Integer): TSomeClass;
begin
 try
   Result := TSomeClass(FItems.Items[i]);
 except
   Result := nil;
 end;
end;

procedure TSomeClassContainer.SetItem(Index: Integer;
 const Value: TSomeClass);
begin
 TSomeClass(FItems.Items[Index]).Assign(Value);
end;

end.


В данном варианте контейнер спрятан в private и доступ к нему идёт через public-функции.


 
Ega23 ©   (2009-02-11 14:25) [13]

type

 TSomeClass = class (TObject)
 private
  FField1 : Integer;
   FField2: string;
 public
  procedure Assign(source : TSomeClass);
  property Field1 : Integer read FField1 write FField1;
  property Field2 : string read FField2 write FField2;
 end;

 TSomeClassContainer = class (TObjectList)
 private
   function GetItem(Index: Integer): TSomeClass;
 public
   property Items[Index : Integer] : TSomeClass read GetItem;
 end;
implementation

{ TSomeClass }

procedure TSomeClass.Assign(source: TSomeClass);
begin
 FField1 := source.FField1;
 FField2 := source.FField2;
end;

{ TSomeClassContainer }

function TSomeClassContainer.GetItem(Index: Integer): TSomeClass;
begin
 Result := TSomeClass(inherited GetItem(Index));
end;

end.


Тут уже никаких "пряталок" в контейнере, всё на свой страх и риск.


 
Ega23 ©   (2009-02-11 14:28) [14]


> но как-то не хотелось городить класс для, вобщем-то, простой
> структуры.


Какая разница? Что класс, что рекорд. Ну перепиши вместо

TSomeRec = record
field1: integer;
field2: string;
end;

сделай

TSomeRec = class
public
field1: integer;
field2: string;
end;


 
SingleStranger   (2009-02-11 14:29) [15]


> Ega23 ©   (11.02.09 14:20) [12]

Хм...
Проще некуда =)))))
И это из структурки из двух полей =)))) Впору новый юнит под эту структуру выделять =))

Но, всеравно спасибо. Если ничего не нарою, то воспользуюсь.


 
Ega23 ©   (2009-02-11 14:32) [16]


> Хм...
> Проще некуда =)))))
> И это из структурки из двух полей =)))) Впору новый юнит
> под эту структуру выделять =))


смотри [13], там гораздо проще. Но в [12] можно сделать более безопасно. Например, с проверками диапазона Index. Чтобы он не List index out of bounds выдавал, а что-нибудь другое.

Всё от логики зависит. Я и тот и другой методы использую, в зависимости от ситуации.


 
Anatoly Podgoretsky ©   (2009-02-11 14:59) [17]

> SingleStranger  (11.02.2009 14:10:11)  [11]

А что тебя смущает, у тебя же уже есть одно индексное свойство, почему бы не добавить еще два.


 
SingleStranger   (2009-02-11 15:24) [18]


> Anatoly Podgoretsky ©   (11.02.09 14:59) [17]
> А что тебя смущает

Если честно, то не понимаю реализации.


 
Sapersky   (2009-02-11 15:36) [19]

Самый простой и быстрый (но наименее расширяемый и безопасный) вариант:

TRecArray = array of TRec;

TSomeClass = class
private
  FSRec: TRecArray;
public
  property SRec: TRecArray read FSRec;
end;


 
Anatoly Podgoretsky ©   (2009-02-11 15:45) [20]

> SingleStranger  (11.02.2009 15:24:18)  [18]

А не надо реализовывать неверные решения, сделай класс.


 
MsGuns ©   (2009-02-11 16:02) [21]

Чтобы пожарить яичницу непременно надо завести птицефабрику или пихание классов куда попало во имя самих классов - отсюда и косяки с граблями


 
Ega23 ©   (2009-02-11 16:04) [22]


> Чтобы пожарить яичницу непременно надо завести птицефабрику
> или пихание классов куда попало во имя самих классов - отсюда
> и косяки с граблями


Правильно! Фтопку классы! Все на асм!


 
MsGuns ©   (2009-02-11 16:16) [23]

>Ega23 ©   (11.02.09 16:04) [22]
>Правильно! Фтопку классы! Все на асм!

Ерничать не надо. Но вот зачем там, где нужна просто организация хранения нелинейных данных (вполне умещающихся в рекорды + списки (массивы)), городить классы с горою абсолютно ненужного кода ? Ну если уж не охота морочиться с созданием-уничтожением рекордов, можно использовать коллекции..


 
Ega23 ©   (2009-02-11 16:22) [24]


> Но вот зачем там, где нужна просто организация хранения
> нелинейных данных (вполне умещающихся в рекорды + списки
> (массивы)), городить классы с горою абсолютно ненужного
> кода ?


Где ты массу ненужного кода видишь?
И потом, для корректного доступа к этим данным, один фиг придётся тот самый "ненужный" код городить.


 
MsGuns ©   (2009-02-11 16:30) [25]

>Ega23 ©   (11.02.09 16:22) [24]
>Где ты массу ненужного кода видишь?

Тебе пальцем ткнуть во все эти пропертя и Get/SetValue или сам посмотришь на свой же "лишний" (к данном случае ессно) код ?
Так это еще пример с двумя полями, а если полей 20, да еще вложенность - я представляю, сколько сотен строчек кода займет у тебя реализация классами :)


 
Ega23 ©   (2009-02-11 16:42) [26]


> Тебе пальцем ткнуть во все эти пропертя и Get/SetValue или
> сам посмотришь на свой же "лишний" (к данном случае ессно)
> код ?


Ты вообще внимательно посмотрел на него? [12] и [13] - 2 разных подхода к организации коллекции.
В первом случае всё упрятано в private, а методы доступа, фактически, повторяют методы TObjectList. Но тут ты уже можешь закладывать проверки каких-то значений, соглашаться или не соглашаться добавлять элемент в коллекцию (по каким-то критериям), проверять диапазон индекса и возвращать не Exception а что-то другое и т.п.
Во втором случае - абсолютно тупое наследование TObjectList с переопределённым Items и GetItem, чтобы не нужно было каждый раз приводить TObject к TSomeClass

var
 i : Integer;
begin
 for i:=0 to List.Count-1 do
  if TSomeObject(List.Items[i]).Field1 = что-то then
   TSomeObject(List.Items[i]).Field2 := ещё_что-то;
end;


А если в определении property Items[...] в конце ещё директиву default добавить, то вышестоящий код будет выглядеть

var
 i : Integer;
begin
 for i:=0 to List.Count-1 do
  if List[i].Field1 = что-то then
   List[i].Field2 := ещё_что-то;
end;


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


 
MsGuns ©   (2009-02-11 16:49) [27]

"Фишка" реализуется простым with и опять-таки нафих классы :)


 
SingleStranger   (2009-02-11 17:26) [28]


> MsGuns ©   (11.02.09 16:49) [27]

Ну дык, предложи свою реализацию. И мы все подивимся, что, оказывается, можно и так!


 
sniknik ©   (2009-02-11 17:44) [29]

> Ну дык, предложи свою реализацию.
предлагаю... хотя я не он.

для
> Динамический массив структур (record)
использовать рекордсет (рекордсет даже переводится как "набор рекордов"... а у то что он динамический вне всякого сомнения)

> как свойство класса.
а класс не нужен.


 
sniknik ©   (2009-02-11 17:45) [30]

а у то ... = ну а то ...


 
Jeer ©   (2009-02-11 18:15) [31]

Тоже не вижу необходимости лишний раз в классах - просто привычка, видимо, создается.

Вот два варианта работы со списками record

type Tabc = record
   A: boolean;
   B: integer;
   C: string;
  end;

type pABC = ^Tabc;

const
    N = 10;

var
   arABC: array of pABC;
   lstABC: TList;
   p: pABC;

// Create
 lstABC := TList.Create;
 SetLength(arABC,N);
 for i:= 0 to N-1 do begin
   New(p);
   lstABC.Add(pABC(p));
   arABC[i] := pABC(p);
 end;

// Destroy
 for i:= 0 to N-1 do begin
   if  pABC(lstABC[i]) <> nil then
     dispose(pABC(lstABC[i]));
 end;
 SetLength(arABC,0);
 lstABC.Free;

// Запись через массив
 arABC[0].A := True;
 arABC[0].B := 1000;
 arABC[0].C := "String";

// Запись через список
 p := pABC(lstABC[0]);
 p.A := True;
 p.B := 1000;
 p.C := "String";

// Чтение
 ShowMessage(arABC[0].C);

 p := pABC(lstABC[0]);
 ShowMessage(p.C);


 
Ega23 ©   (2009-02-11 18:27) [32]


> Вот два варианта работы со списками record


Ну нормальные варианты. Только я бы всё-таки потомка от TList написал. Дабы dispose каждый раз руками не дёргать.

Но если начать всё это дело обкладывать дурако-защитными вещами - то употеешь.
Т.к. мне никто не помешает сделать так:

SetLength(arABC,N);
for i:= 0 to N-1 do begin
  New(p);
  arABC[i] := pABC(p);
end;


А потом
New(p);
arABC[3] := p;


И аля-улю.
Т.е. мне каждый раз надо прописывать
p1 := arABC[3];
arABC[3] := p;
Dispose(p1);


Если это всё нужно один единственный раз сделать - ну можно. А если 5 раз? А 50?
А так один раз класс написал, что-то типа:


 TSerializedItem = class (TObject)
 protected
   FItemTag : Integer;
   procedure ReadStreamData(stream : TStream; bh : TBH); virtual; abstract;
   function GetItemSize : Integer; virtual; abstract;
 public
   constructor Create; virtual;

   procedure Assign(Source : TSerializedItem); virtual; abstract;
   procedure LoadFromStream(stream : TStream); overload;
   procedure LoadFromStream(stream : TStream; const DataSize : Integer); overload;
   procedure SaveToStream(stream : TStream); virtual;

 end;

 TSerializedItemClass = class of TSerializedItem;

 TSerializedItemsList = class (TObjectList)
 private
   function GetItem(Index: Integer): TSerializedItem;
   function GetItemSize : Integer;
 protected
   FItemTag : Integer;
   FSelfTag : Integer;
   FItemClass : TSerializedItemClass;
 public
   constructor Create; virtual;

   procedure Assign(Source : TSerializedItemsList);
   procedure LoadFromStream(stream : TStream); overload;
   procedure LoadFromStream(stream : TStream; const DataSize : Integer); overload;
   function AddNewItem : TSerializedItem;
   procedure SaveToStream(stream : TStream);

   property Items[Index : Integer] : TSerializedItem read GetItem; default;
   property ListSize : Integer read GetItemSize;
   property TagID : Integer read FSelfTag;
 end;

 TSerializedItemsListClass = class of TSerializedItemsList;


И гоняй его потом, как хочешь, особо не задумываясь.


 
Sapersky   (2009-02-11 18:41) [33]

"Фишка" реализуется простым with

Видимо так:

PRec = ^TRec;
TSomeClass = class
private
  function GetSRec(Index: Integer): PRec;
public
  property SRec[Index: Integer]: PRec read GetSRec;
end;

function TSomeClass.GetSRec(Index: Integer): PRec;
begin
Result := @FSRec[Index];
end;

...
begin
With SomeClass.SRec[i]^ do begin
 field1 := 1;
 field2 := "bbb";
end;

Хотя из дополнительных возможностей, которые дают Get/Set функции, здесь можно реализовать только контроль индексов.

Jeer ©   (11.02.09 18:15) [31]

Слава рЕкордам! Сотрём все классы! :)
http://sapersky.narod.ru/files/Arrays.rar
(Arr_AddItem, Arr_DelItem)


 
Jeer ©   (2009-02-11 18:41) [34]


> Ну нормальные варианты. Только я бы всё-таки потомка от
> TList написал. Дабы dispose каждый раз руками не дёргать.
>


Да понятно это все - но если плохо понимаешь, что делаешь - известна рекомендация "Займись тем, что у тебя получается"


 
Jeer ©   (2009-02-11 18:46) [35]

Да я вообще могу вас отправить в Delphi Fundamentals
Там, пожалуй, все дельфинячьи "радости" сосредоточены. :)
В том числе и такого типа.

http://fundementals.sourceforge.net


 
Джо ©   (2009-02-11 18:50) [36]


> http://fundementals.sourceforge.net

We"re Sorry but this Project hasn"t yet uploaded their personal webpage yet.
:)


 
Ega23 ©   (2009-02-11 18:54) [37]


> Да понятно это все - но если плохо понимаешь, что делаешь
> - известна рекомендация "Займись тем, что у тебя получается"


Возможно у меня это просто на автомате уже получается. Ну не люблю я рекорды. Я ещё могу понять record в случае записи в файл типизированный или там при передаче по сети какой-нибудь. Но в данном конкретном случае (как у автора) я класс бы не задумываясь написал. Тем более, что если понадобится - всегда можно геттеры и сеттеры прикрутить. Лёгким движением руки.


 
Jeer ©   (2009-02-11 20:17) [38]


> Джо ©   (11.02.09 18:50) [36]
We"re Sorry but this Project hasn"t yet uploaded their personal webpage yet.
:)


Да не проблема:
http://sourceforge.net/projects/fundementals/

Давно слежу за развитием проекта David J Butler, еще со времен динозавров.
Не ошибусь, если скажу, что с первыми релизами я ознакомился еще в прошлом веке.
Пользуюсь, не всегда, но пользуюсь.

Отличная подборка классов и утилит по структурам данных, математике, потокам, системным/интернет/xml и прочее.

Просто рекомендую всем, кто не знаком с данной библиотекой - хотя бы для "изучительных" целей.

Того оно стоит.


 
SingleStranger   (2009-02-11 20:32) [39]

Давайте я попробую приближенно описАть задачу. Может быть предложите другое решение.

Например есть класс-поток, который постоянно (ПОСТОЯННО) рисует человека. Есть структура описывающая одежду человека;
TRec = record
 DressCode: integer; // штаны, например. рубашка, шляпа, и т.п.
 Color1: TColor;
 Color2: TColor;
 Color3: TColor;
 Style: integer;
end;


Ну, можно еще десяток полей придумать, не важно.
Так вот, у класса рисующего человека есть (должен быть, по задумке) динам. массив этих TRec"ов и на основании него он прорисовывает, перебирая весь массив, одежду. Но массив может быть и пуст, а может быть наполнен 10-20 предметами.
Но при этом, ВСЕГДА есть трусы =) описанные ТОЙ ЖЕ структурой и реализованные как свойств класса, через указатель (примерно так, как предлагал MsGuns (Стволы от Майкрософт, что ли? ;) ) и Sapersky [33]), т.е. они есть всегда. И в общем-то преход к другой структуре возможен, но... Надо будет просто переписать некоторые другие вещи, непосредственно к сабжу не относящиеся.
Вот отсюда и сабж. Как реализовать набор одежды, описанной структурой TRec.

P.S. Не стоит придираться к деталям, это приближенное описание.


 
Jeer ©   (2009-02-11 20:39) [40]

P.S.
Кста - под НГ вышел, оказывается, новый релиз v 4.
Батлер опять слил все в единый каталог - пральна.

Посмотрел.. по ср. с v.3* - хорошо переработано.

Однако исчезла математике ( вроде как )

Ну и ладно - не ему спорить с современными алгоритмами - у него всегда была простая, не особо эффективная, но работающая реализация:
- векторы, матрицы, компл. числа, рац.числа, статистика, 3D преобразования и пр.

Хотя жаль - довесок неслабый был.

Впрочем, по ссылке, доступны старые версии 3.* - там это должно быть.



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

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

Наверх





Память: 0.58 MB
Время: 0.008 c
3-1217676103
VadimSpb
2008-08-02 15:21
2009.04.05
Символ # в имени таблицы


15-1233903496
desc
2009-02-06 09:58
2009.04.05
Выпустить денвер на ружу....


2-1234501149
Гарик
2009-02-13 07:59
2009.04.05
OnShow(self)


4-1201570363
Legolas
2008-01-29 04:32
2009.04.05
Программа для блокировки


15-1233823377
Alkid
2009-02-05 11:42
2009.04.05
Посоветуйте видеокарту.





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