[SourcePawn] Урок 4 - Форматирование текста и мультиязычность

R1KO

fuck society
Сообщения
9,457
Реакции
7,786
  • Команда форума
  • #1
[SourcePawn] Урок 4 - Форматирование текста и мультиязычность

<- К содержанию

  • Форматирование текста (строк)
    Для этой задачи используются функции Format, FormatEx и VFormat.
    Эти функции получают в качестве аргументов:
    • Строку (буфер), куда будет записан результат
    • Максимальный размер буфера (чтобы не выйти за пределы),
    • Правило формата
    • Аргументы для подстановки
    Пример:
    PHP:
    char szBuffer[128];
    Format(szBuffer, sizeof(szBuffer), "Игрок: %N, убийств - %i, смертей - %i", iClient, GetClientFrags(iClient), GetClientDeaths(iClient));
    В результате мы получим такую строку:
    PHP:
    "Игрок: R1KO, убийств - 4, смертей - 2"
    Как вы поняли функция заменяет все эти %N, %i и т.д. на аргументы, которые ей передали.
    Типы данных для форматирования:
    • Численные
      • %i или %d - Целое число (%u - беззнаковое, только положительные значения)
        PHP:
        FormatEx(szBuffer, sizeof(szBuffer), "Число - %i", 5);
        Результат:
        PHP:
        "Число - 5"
      • %b - Двоичный тип (выводит значение в двоичном виде отсекая ноли слева)
        PHP:
        FormatEx(szBuffer, sizeof(szBuffer), "Значение #1 - %b, Значение #2 - %b", true, 13);
        Результат:
        PHP:
        "Значение #1 - 1, Значение #2 - 1101"
      • %f - Число с запятой (дробное)
        PHP:
        FormatEx(szBuffer, sizeof(szBuffer), "Число - %f", 16.3);
        Результат:
        PHP:
        "Число - 16.300000"
        По умолчанию после запятой выводится 6 знаков.
        Это число можно изменить:
        PHP:
        FormatEx(szBuffer, sizeof(szBuffer), "Число - %.2f", 16.3); // Указываем что будет выводиться только 2 знака после запятой
        Результат:
        PHP:
        "Число - 16.30"
      • %x или %X - Шестнадцатеричное представление двоичного значения
        PHP:
        FormatEx(szBuffer, sizeof(szBuffer), "Число - %x", 75);
        Результат:
        PHP:
        "Число - 00004B"
    • Символьные
      • %s - Строка
        PHP:
        FormatEx(szBuffer, sizeof(szBuffer), "Строка - %s", "my_string");
        Результат:
        PHP:
        "Строка - my_string"
      • %c - Символ
        PHP:
        FormatEx(szBuffer, sizeof(szBuffer), "Символ - %c", 'r');
        Результат:
        PHP:
        "Символ - r"
      • %t и %T - Перевод фразы (подробнее будет дальше)
    • Специальные
      • %N - Ник игрока. Аргументом передается индекс игрока
        PHP:
        FormatEx(szBuffer, sizeof(szBuffer), "Ник - %N", iClient);
        Результат:
        PHP:
        "Ник - R1KO"
      • %L - Данные игрока (Ник <юзерид><стимид><>). Аргументом передается индекс игрока
        PHP:
        FormatEx(szBuffer, sizeof(szBuffer), "Игрок - %L", iClient);
        Результат:
        PHP:
        "Игрок - Tonki_Ton<406><STEAM_1:0:81729330><>"
    • Больше информации можно найти здесь: printf - C++ Reference и здесь printf — Википедия

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

    В чем же отличие функций Format, FormatEx и VFormatмежду собой?
    • Format - Форматирует строку в соответствии с правилами формата
    • FormatEx - Форматирует строку в соответствии с правилами формата, отличается от Format тем, что у FormatEx входным аргументом не может быть та же строка. Работает быстрее чем Format.
      PHP:
      char szBuffer[128];
      strcopy(szBuffer, sizeof(szBuffer), "my_string");    // Записываем в szBuffer значение "my_string"
      Format(szBuffer, sizeof(szBuffer), "Значение - %s", szBuffer);    // Передаем аргументом ту же строку, в которую будет помещен результат
      С FormatEx такие фокусы не проходят. По идее это может и будет работать, но как написано в api:
      This is the same as Format(), except none of the input buffers can overlap the same memory as the output buffer. Since this security check is removed, it is slightly faster.
    • VFormat - Форматирует строку в соответствии с правилами формата, но правила формата принимает не как аргумент, а как параметр функции.
      PHP:
      void MyFunc(const char[] szFormat, any ...)
      {
          int iLen = strlen(szFormat) + 255;    // Получаем длину строки с правилами формата и прибавляем запас нужный для подстановки значений
          char[] szBuffer = new char[iLen];    // Создаем буфер с полученным размером
          VFormat(szBuffer, iLen, szFormat, 2);    // 2 это номер параметра any ... в заголовке функции.
          // В нашем случае 1-й параметр это szFormat, а 2-й уже any ...
          // Само объявление any ... означает что в функцию может передаваться любое количество аргументов
          // В функции эти параметры являются скрытыми
          PrintToServer("Результат VFormat: %s", szBuffer);
      }
      
      // Вызываем нашу функцию:
      MyFunc("Число: %i, Строка: %s", 5, "my_string");
      // Получаем
      "Результат VFormat: Число: 5, Строка: my_string"
      Это используется для создания собственных функций с форматированием. (Например, morecolors, csgo_colors)
  • Мультиязычность
    Мультиязычность позволяет выводить игрокам сообщения (в чат, меню, консоль и вообще куда только можно) в зависимости от языка клиента игрока.

    Для работы с мультиязычностью важно знать такие термины:
    • Языки - предварительно заданные языки перевода устанавливаются в configs\languages.cfg. Если язык перевода отсутствует в этом файле, он не может быть переведен до тех пор, пока не будет добавлен в этот файл и обновлена кэш-память переводов.
    • Фразы/Ключи перевода - Короткие, общие ключевые фразы, используемые для определения набора переводов. Они находятся в конфигурационных файлах в папке translations. Они называются файлы перевода.
    • Переводы - Содержат фразы текста перевода для данного языка. Они находятся в файлах перевода.
    • Файлы перевода - файлы с расширением .phrases.txt, которые расположены в addons/sourcemod/translations/
    • Примечание: Переводы и Фразы, чувствительны к регистру.


    Для использования файла перевода его необходимо подключить к плагину:
    PHP:
    LoadTranslations("my_file.phrases");
    При этом файл должен будет иметь название: my_file.phrases.txt

    Плагины должны вызывать функцию LoadTranslations на каждый файл с переводом, который они хотят использовать. Если это не будет сделано, то никакие переводы работать не будут, даже если другой плагин загрузил те же самые файлы. Это поможет предотвратить конфликты фраз между плагинами.

    Фразы находятся в файлах перевода, которые имеют такую структуру:
    PHP:
    "Phrases"
    {
        "MyPhrase"    // Имя фразы
        {
            "en"        "My Phrase"        // Перевод фразы для языка с кодом en
            "ru"        "Моя фраза"        // Перевод фразы для языка с кодом ru
        }
    
        "Welcome"
        {
            "en"        "Welcome to SourceMod"
            "ru"        "Добро пожаловать в SourceMod"
        }
    
        "ClientConnected"
        {
            "#format"    "{1:N}"
            "en"        "Playe {1} joined"
            "ru"        "Игрок {1} подключился"
        }
    }
    Ключ "#format" задает количество параметров, для подстановки и их тип. Нумеруются они в том порядке в каком были переданы аргументы в функцию форматирования.
    PHP:
    FormatEx(szBuffer, sizeof(szBuffer), "%t", "MyPhrase", 123, "my_string", 22.4);
    В файле перевода:
    PHP:
    "Phrases"
    {
        "MyPhrase"    // Имя фразы
        {
            "#format"    "{1:i},{2:s},{3:f}"
            "en"        "int value: {1}, string value: {2}, float value: {3}"
            "ru"        "целое значение: {1}, строчное значение: {2}, дробное значение: {3}"
        }
    }
    Но в самом переводе они могут меняться местами:
    PHP:
    FormatEx(szBuffer, sizeof(szBuffer), "%t", "MyPhrase", 123, "my_string", 22.4);
    В файле перевода:
    PHP:
    "Phrases"
    {
        "MyPhrase"    // Имя фразы
        {
            "#format"    "{1:i},{2:s},{3:f}"
            "en"        "string value: {2}, int value: {1}, float value: {3}"
            "ru"        "строчное значение: {2}, целое значение: {1}, дробное значение: {3}"
        }
    }
    В ключе "#format" мы сообщаем:
    • Параметр №1 имеет тип int
    • Параметр №2 имеет тип char
    • Параметр №3 имеет тип float
    Типы были описаны в начале урока.
    • Когда использовать %t, а когда %T?
      • %t используется если форматирование происходит после SetGlobalTransTarget.
        Функция SetGlobalTransTarget устанавливает индекс игрока, для языка которого в данный момент будет выполняться форматирование. Если её аргумент равен 0 или LANG_SERVER то форматирование будет выполнено для языка сервера.
        PHP:
        SetGlobalTransTarget(iClient);
        FormatEx(szBuffer, sizeof(szBuffer), "Перевод: %t", "MyPhrase", 123, "my_string", 22.4);
        В функциях PrintToChat, PrintToChatAll, PrintCenterText, PrintCenterTextAll, PrintHintText, PrintHintTextToAll присутствует функция SetGlobalTransTarget, поэтому при форматировании текста в них нужно писать %t.
      • %T требует чтобы 2-м аргументом (1-й это фраза) передавался индекс игрока, для которого будет выполняться форматирование.
        PHP:
        FormatEx(szBuffer, sizeof(szBuffer), "Перевод: %T", "MyPhrase", iClient, 123, "my_string", 22.4);    // 2-й аргумент - индекс игрока
        Следовательно этот код аналогичен этому:
        PHP:
        SetGlobalTransTarget(iClient);
        FormatEx(szBuffer, sizeof(szBuffer), "Перевод: %t", "MyPhrase", 123, "my_string", 22.4);
        Так же %T не допускает использования фразы внутри перевода:
        PHP:
        SetGlobalTransTarget(iClient);
        FormatEx(szBuffer, sizeof(szBuffer), "%t", "MyPhrase", "MyPhrase2");

        В файле перевода:
        PHP:
        "Phrases"
        {
            "MyPhrase"    // Имя фразы
            {
                "#format"    "{1:t}"
                "en"        "My Phrase: {1}"
                "ru"        "Моя фраза: {1}"
            }
            "MyPhrase2"    // Имя фразы
            {
                "en"        "My Phrase 1"
                "ru"        "Моя фраза 2"
            }
        }
        Здесь фраза "MyPhrase2" передана аргументом для форматирования фразы "MyPhrase".
        Т. е. вместо {1} будет подставлен перевод фразы "MyPhrase2".
        Но это доступно только для %t, с %T так делать нельзя.
    Чтобы вывести просто символ процента % нужно написать %%

Источники:
 
Последнее редактирование:

SolarCore

Участник
Сообщения
40
Реакции
24
"ClientConnected"
{
"#format" "{1:N}"
"en" "Playe {1} joined"
"ru" "Игрок {1} подключился"
}
Заместо Playe надо Player
 

GUM

Участник
Сообщения
82
Реакции
15
CPrintToChatEx(
i,
i,
"{green}(Чат){teamcolor} %N: Ребят мне требуется ?? голосов чтобы сменить карту!",
name,
rtv_threshold - size
);

А как здесь быть, если нужен ответ? rtv_threshold - size
 

R1KO

fuck society
Сообщения
9,457
Реакции
7,786
  • Команда форума
  • #5
@artem51525, ну если rtv_threshold имеет тип int то вместо ?? нужно %d или %i
 

GUM

Участник
Сообщения
82
Реакции
15
@artem51525, ну если rtv_threshold имеет тип int то вместо ?? нужно %d или %i
Я пробывал целые числа, но сервер вообще каким то образом падал(без логов\ошибок), приложу исх. Строки 755 и 775, делал как будто сообщение от клиента со звуком в чат идёт. И строка 703 , почему- то секунды в шестизнач. показывает.
 

Вложения

  • umc-rockthevote2.sp
    32.9 КБ · Просмотры: 21

GUM

Участник
Сообщения
82
Реакции
15
%N замени на %s или name на i
Мне конкретнее это нужно
CPrintToChatEx(
i,
i,
"{green}(Чат){teamcolor} %N: Ребят мне требуется ?? голосов чтобы сменить карту!",
name,
rtv_threshold - size
);

А как здесь быть, если нужен ответ? rtv_threshold - size
 

R1KO

fuck society
Сообщения
9,457
Реакции
7,786
  • Команда форума
  • #9
@artem51525, Судя по тому что есть в исходнике
PHP:
CPrintToChatEx(
                        i,
                        i,
                        "{green}(Чат){teamcolor} %s: Ребят мне требуется %d голосов чтобы сменить карту!",
                            name,
                            rtv_threshold - size
                    );
 
  • Мне нравится
Реакции: GUM

alexmy

Участник
Сообщения
284
Реакции
13
Интересует, возможно сделать мультиязычность в самом исходники чтоб не создавать TXT?
 
  • Мне нравится
Реакции: GUM

GUM

Участник
Сообщения
82
Реакции
15
Интересует, возможно сделать мультиязычность в самом исходники чтоб не создавать TXT?
Благодарю, не использую. Перевожу лишь на один все исх. т.к для каждого перевода нужно делать оформление для крас. интер. , да и не заходят к нам иностранцы.
 

R1KO

fuck society
Сообщения
9,457
Реакции
7,786
  • Команда форума
  • #15
@alexmy, ничего не удобнее. хранить фразы и тексты в исходнике глупо, он должен выполнять действия, а не хранить данные.
Удобнее прописать 1 строку в исходнике (подключение перевода) и использовать коротенькие фразы чем создавать массивы (тут скорее trie), писать ф-и для поиска фразы, ф-и для парсинга и форматирования текста + получение и выбор языка.
 

Danyas

Участник
Сообщения
2,173
Реакции
1,072
А в фразах перевода возможен ли перевод строки? \n который
 

R1KO

fuck society
Сообщения
9,457
Реакции
7,786
  • Команда форума
  • #17
@Danyas, в самом файле перевода? попробуй \\n или alt + 0A
 

8Ahnenerbe8

Участник
Сообщения
113
Реакции
30
PHP:
int iLen = strlen(szFormat) + 255;
char[] szBuffer = new char[iLen]; 
VFormat(szBuffer, sizeof(szBuffer), szFormat, 2);
->>>
PHP:
int iLen = strlen(szFormat) + 255;
char[] szBuffer = new char[iLen]; 
VFormat(szBuffer, iLen, szFormat, 2);
 

R1KO

fuck society
Сообщения
9,457
Реакции
7,786
  • Команда форума
  • #20
@8Ahnenerbe8, так нельзя делать. компилятор не даст такое скомпилить
 
Сверху Снизу