Multi-Languages -
White_116 - 24.12.2014
Доброго времени суток.
Перед новым годом принято дарить подарки и я хочу представить результат проделанной мной работы.
Хочу представить вам небольшой include, который позволит вам
без труда сделать
мультиязычный сервер. На написание includ-а меня сподвиг tutorial
Мультиязычный интерфейс.
В данном tutorial-е рассмотренный классические схемы построения мультиязычного сервера, но данные схемы
неудобны при написании больших модов, некие схемы с точки зрения производительности
пагубны для сервера, третьи имеют
плохую плотность данных, происходит выделение большого количества памяти для хранения текста, которые в свою очередь не заполняет всю память, выделенной для её хранения. Пример:
-
Первым направлением было, решение плотности хранения данных (текста). Для это пригодились особенности строкового типа, а именно определения конца текста. Был создан одно длинное хранилище всех текстов. Особенностью решения является то, что все тексты пишутся друг за другом - потоком. Достигается высокая плотность хранения данных, так как под каждый текст не выделяется своя переменная заданной длины.
-
Вторым направление было, повышение удобства программирования. Каждый из вас согласится с тем, что запоминать кучу идентификаторов текста, как число, очень не удобно и даже отталкивает. Возьмём пример из tutorial-а
pawn Code:
SendClientMessage(playerid, 0xFDE39DFF, Language[GetPVarInt(playerid, "Language")][0]);
Попробуй пойми, что там за текст хранится, а постоянно подглядывать в файл та ещё забава. Другое дело запомнить идентификатор как текст на много легче, создаются ассоциации. Пример:
pawn Code:
#define RUS_TEXT_TWO "Текст %s текст"
#define ENG_TEXT_ONE "Text %s text"
Но тут мы сталкиваемся с проблемами, как мы все знаем текст будет подставятся препроцессором компилятора, и тогда чтобы осуществить мультиязычность - нужны условия, какой язык сервер будет показывать. Так же, стандартный компилятор не может скушать текст более 512 символов, что не позволительно в некоторых диалоговых окнах. Так же в tutorial-е была реализация подстановки текста по имени ключа в файле, но мы же с вами грамотные люди, мы знаем к чему всё это приводит. И тут, многим покажется, что решений больше нет, но тут я применил маленькую хитрость. Особенность
enumenator-a, поля в нём имеют текстовое представление и они уже изначально индексируются. Объясню наглядно:
pawn Code:
enum Text
{
Text_1[32],
Text_2[32],
};
new var[2][Text];
//...
var[1][Text_2] = "123"; /*тоже самое что и*/ var[1][1] = "123";
//Пример:
SendClientMessage(playerid, 0xFDE39DFF, Language[GetPVarInt(playerid, "Language")][Text_2]);
Теперь уже мы интуитивно понимаем, что за текст там может содержатся. Но остаётся вопрос, как же это всё связывается.
Так как у нас буффер большой длины и нужно извлекать необходимые тексты, требуется знать место(ячейку) с которого начинается текст. Для этого создана переменная, которая хранит указатель на ячейку с которого начинается текст, текст у нас ассоциируется с полем
enumenator-a, а само поле выступает в качестве идентификатора. (смотри код в includ-e

)
-
Третьим направление было, хранение текстов и их размещение. Самым удобным вариантом, конечно же является хранения текстов в файле, его можно в любое время открыть, подредактировать. Обычно структура таких файлов является:
[ключ]текст, но это нужно писать обработчик, поиск ключей, проверять ключ по условию чтобы положить в нужную переменную и т.д. Решение оказалось на удивление простым. Был взят
enumenator и вынесен в отдельный файл, а рядом с полем написаны тексты. Выглядит это всё следующим образом:
pawn Code:
enum E_Lng {
Error_Localization/*системная строка*/,//Ошибка локализации.
Localization,//Русский
asdasd_2,//резервная строка
Line_1,//Я строка номер %s, моя длина %d символов.
Line_2,//Я строка номер %s, моя длина %d символов и я длиннее.
Line_3,//Я строка номер %s, моя длина %d символов,\r\nкто следующий?.
};
Ассоциация и рядом сам текст, здорово, не правда ли. Причём вы можете перемещать строки не боясь о том что потеряете идентификатор, так как Ассоциация(поле
enumenator-а) автоматически индексируется. Дополнительно к этому при удалении строки или её отсутствии, не позволит программисту сделать ошибку, если данный текст ещё используется в коде. Размер длины текста не имеет значения, главное что бы текст был положен в одну строку. Возможность оставлять комментарии и много других не явных функций.
Основным условием является формирование строки вида:
*,//*
Закончим вводную часть.
Преимущества данного includ-а:
- Поддержка большого количества локализаций, по умолчанию до 256.
- Локализация хранится в файле.
- Возможность быстрой правки локализации и задействование её не перезагружая сервер.
- Хорошая плотность данных.
- Стабильная и достаточна быстрая работа.
- Лёгкость в программировании, по сравнению с другими схемами.
- Система контроля ошибок.
Недостатки:- Нельзя добавлять тексты(строка) без перекомпиляции мода. Особенно если текст(строка) добавлен в середине файла локализации - вызывает смещение данных.
- Для того, чтобы на ходу делать правки, расширять тексты, нужно предварительно выделить больше ячеек памяти. отвечает за это #define MAX_ML_CHARACTER
- При добавлении новых локализаций, необходимо учесть два минуса, указанных выше и соответственно вписать файл в ML_Text_Files
Функции:
pawn Code:
ML_Load(); //Загружает/перезагружает локализации.
ML_Text(lngid, textid); //Возвращает текст. Параметры: (ид языка, ид текста)
ML_Player_Text(playerid, textid); //Возвращает текст c учётом установленного языка для игрока Параметры: (ид игрока, ид текста)
ML_S_Text(language, E_Lng:text, source[], len = sizeof(source)); //Безопасное перекладывание текста. Возвращает истину если успешно переложено. Параметры: (ид языка, ид текста, название массив, длина массива)
ML_S_Player_Text(playerid, E_Lng:text, source[], len = sizeof(source)); //Безопасное перекладывание текста c учётом установленного языка для игрока. Возвращает истину если успешно переложено. Параметры: (ид языка, ид текста, название массив, длина массива)
ML_SetPlayerLanguage(playerid, language); //Установка языка игроку, Вернёт истуну в случае успеха. Параметры: (ид игрока, ид языка)
Установка:- Скачать архив.
- Распаковать в папку с сервером.
- В моде подключить следующим образом: #include "../include/ML.inc"
- Подстроить настройки в includ-e
Пример использования:
pawn Code:
#include <a_samp>
#include "../include/ML.inc" // Мультиязычность.
public OnFilterScriptInit()
{
ML_Load(); // Загрузим локализации
print(ML_Text(0, Localization)); // Выведем в консоль текст
new source[16];
if(ML_S_Text(0, Line_1, source)) //Безопасно извлекаем строку
{
print(source); // Выведем в консоль текст
}
else
{
print("Строка не была извлечена!");
}
new source_2[64];
format(source_2, sizeof(source_2), ML_Text(0, Line_2), "два" ,strlen(ML_Text(0, Line_1)));// Формируем текст
print(source_2); // Выведем в консоль текст
print(ML_Text(1, Line_3));
return 1;
}
Скачать:
Версия 1.0: >>> solidfiles.com инклуд+локализации+пример
Просмотреть:
Версия 1.0: >>> pastebin.com
Re: Multi-Languages -
Jon_De - 25.12.2014
не легче просто короткие сообщения дефайнить, а длинные в массиве хранить? использование то всё равно одинаковое
Re: Multi-Languages -
ea8de1 - 25.12.2014
translate.inc удобней же
Re: Multi-Languages -
OKStyle - 25.12.2014
Имхо у меня в файлах удобнее.
Re: Multi-Languages -
White_116 - 25.12.2014
Quote:
Originally Posted by Jon_De
не легче просто короткие сообщения дефайнить, а длинные в массиве хранить? использование то всё равно одинаковое
|
И как ты собрался сделать отображение текстов на том или ином языке в зависимости от желания игрока. Одновременно сервер получается на нескольких языках.
Quote:
Originally Posted by OKStyle
Имхо у меня в файлах удобнее.
|
Файл постоянно читать нужно, не есть хорошо.