Wake of Gods Forum | Форум Во Имя Богов
Создание скриптов с поддержкой мультиязычности - Printable Version

+- Wake of Gods Forum | Форум Во Имя Богов (http://wforum.heroes35.net)
+-- Forum: Герои Меча и Магии 3.5 WoG/ERA (/forumdisplay.php?fid=99)
+--- Forum: Моды (/forumdisplay.php?fid=104)
+---- Forum: ЭРА / ERA (/forumdisplay.php?fid=182)
+---- Thread: Создание скриптов с поддержкой мультиязычности (/showthread.php?tid=5476)


Создание скриптов с поддержкой мультиязычности - Berserker - 16.02.2020 22:49




1. Формат ERT устарел и не рекомендуется к применению.

2. В папке мода создаётся файл Lang\*.json, например Lang\имя мода.json.

3. Файл имеет следующий формат в кодировке UTF-8:
Code:
{
  "ключ 1-го уровня": {
    "ключ 2-го уровня": {
      "ключ 3-го уровня": "значение",
      "ключ 3-го уровня": "значение"
    }
  }
}

4. Вложенность и количество уровней определяется объёмом текста в моде и личным решением автора мода. Минимальным и достаточным вариантом выступают 1 уровень группировки с аббревиатурой мода и один уровень для каждого конкретного переводимого текста.

Пример для мода Battle Heroes:
Code:
{
  "bh": {
    "skill_diplomacy": "Дипломатия",
    "tournament_win_message": "Вы победили в турнире!"
  }
}

5. В текстах перевода могут быть подстановочные параметры (placeholders), которые в момент перевода должны быть заменены на числа/строки. Такие параметры заключаются между символами "@"..."@".

Пример:
Code:
{
  "bh": {
    "exp_gain_msg": "Вы получили @exp@ опыта"
  }
}

6. Получить перевод из ЕРМ можно через SN:T$1/?$2/[#3/#4...];
$1 - составной ключ перевода, где ключи разных уровней разделяются точками. Пример: ^bh.exp_gain_msg^

?$2 - в какую строку поместить перевод
#3 - название очередного параметра
#4 - значение очередного параметра

Пример:
Предполагается, что в v600 хранится опыт, полученный героем.
Поддерживается до 7-и пар параметр-значение в ЕРМ и неограниченное число в плагинах/Lua.


RE: ERA Scripts 1.41 Rus, Eng - Algor - 17.02.2020 01:14

Вопросы остались.
1. Количество json-файлов в каталоге Lang ограничено? Хочется для каждой опции иметь отдельный языковой файл.
2. Можно ли подтягивать json-файлы из data/s, чтобы языковой файл лежал рядом со скриптом?
3. Как все-таки задать для одного ключа разноязычные значения? Если разными составными частями ключа, типа ^bh.exp_gain_msg.ru^, то как определить используемый язык в ERM, чтобы подставить этот самый "ru" или "en"?

Еще в changelog'е нашел:
Hints from Mod\Data\Buttons\*.btn files are now automatically translated. No need to include *.btn files in localizations.

А в этом случае где задаются и как подтягиваются разноязычные hint'ы? Примера не нашел...


RE: ERA Scripts 1.41 Rus, Eng - Berserker - 17.02.2020 01:22

Algor,
1. Ограниченно возможностями файловой системы. То есть нет.
2. Нет, скрипты Lua/ERM/из карты/плагины могут быть в разных местах, но место файлам локализации в одном универсальном.
3. О языке думать не нужно. Файл json пишется на одном языке. Затем пишется мод-перевод на любой другой язык, например your mod rus.json или your mod pl.json. Я просто добавляю аббревиатуру языка к имени файла. xxx.json оригинал, xxx cn.json для китайского.

Ключи-значения из всех json-файлов всех модов объединяются в один словарь. Ключи из приоритетных модов имеют приоритет. Файлы в модах-локализациях могут иметь произвольные названия, но рекомендуется использовать имя, отличное от файла оригинала.

Пример:
Базовый мод на русском, есть три ключа А, Б, В.
Есть мод-англификатор с каким нибудь XXX eng.json, где только ключ Б.
Игрок будет видеть сообщение Б на английском, а А и В на русском. Если же перекрыть файл полностью, вместо А и В будут названия ключей. Таким образом частичные и устаревшие переводы поддерживаются.


----------------------------------
Для кнопок аналогично, ищется по ключу перевод. Ключ из какого мода приоритетнее, тот и задействован. Посмотри на Quick Savings мод оригинал и его перевод из WoG Rus.


RE: Сборка HoMM3 ERA с модами. - Algor - 17.02.2020 11:18

Berserker Wrote:Затем пишется мод-перевод на любой другой язык, например your mod rus.json
Ну, то есть, все равно отдельный мод в отдельном каталоге? Если да, то печально. Весь смысл вопроса в том, чтобы все языки лежали в одном моде, а для простоты перевода - в одном файле, например:

   "ru_RU": {"skill_diplomacy": "Дипломатия"}
   "en_EN": {"skill_diplomacy": "Diplomacy"}
   "cn_CN": {"skill_diplomacy": "<неведомая клинопись>"}

_Lang.erm:

*.erm:



RE: ERA Scripts 1.41 Rus, Eng - igrik - 17.02.2020 11:38

(16.02.2020 16:40)Algor Wrote:  Berserker, а есть возможность/пример использования SN:T и мультиязычного json? Даже не так: как в игре получить используемый язык?
Если хоть как то поможет, то определение языка (английский или русский) можно использовать так (Подробнее):



RE: ERA Scripts 1.41 Rus, Eng - Algor - 17.02.2020 19:05

Berserker, как вариант можно поставлять в одном моде несколько json-ов в каталоге Lang:
0_en_US.modname.json
1_ru_RU.modname.json.off
2_cn_CN.modname.json.off
3_pl_PL.modname.json.off
...
и инструкцию убрать ".off" у файла для своего языка. en_EN можно не убирать - будет базовым, если в каком-то из переводов не все позиции переведены.
Но это, к сожалению, не решает проблему с локализацией нетекстовых элементов (картинки/голос).
Но для ES количество json'ов будет слишком велико, а сливать тексты всех опций в один файл мне категорически не хочется.


RE: ERA Scripts 1.41 Rus, Eng - Berserker - 17.02.2020 20:12

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

В целом политика такая. Текст, как и картинки с надписями — это просто игровой ресурс. Игра не знает, из каких ресурсов она состоит. Поэтому строгого понятия языка нет. Мод пишется на одном основном языке, как будто других нет. Чаще всего пользователь скачает только одну локализацию из официального или фанатских источников. Другие ему не нужны. Бывает, автор забивает на перевод, люди пользуются альтернативами.


RE: Создание скриптов с поддержкой мультиязычности - ElfbI - 22.02.2020 01:05

Berserker, начиная с какой версии эры работает?


RE: Создание скриптов с поддержкой мультиязычности - Berserker - 22.02.2020 02:58

ElfbI, с 2.6.2.


Algor, тебе достаточно двух модов. Основного и одной локализации на английский. В каждом по папке Lang\*.json с отдельным файлом json для каждой опции, если хочется точечного разбиения.

Quote:"ru_RU": {"skill_diplomacy": "Дипломатия"}
"en_EN": {"skill_diplomacy": "Diplomacy"}
"cn_CN": {"skill_diplomacy": "<неведомая клинопись>"}
Такой подход не даёт раздлетить языковые данные по людям и проектам — это раз. Требует наличия фиксированного основного и резервного языков — это да. Не поддерживает частичный перевод без резервного языка — это три.

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

Quote:Если хоть как то поможет, то определение языка (английский или русский) можно использовать так (Подробнее):

    !!UN:C8401436/4/?y1; [тип языка: 0-английский, 1-русский]
Вот так просьба не делать. Не нужно никаких предположений о языке игры и копаний в памяти. Если у меня *.txt ресурс на польском, мне всё равно, где там код ВоГа костыльно пытается хранить двуязычие, а другие моды костыльно определить мой фиксированный язык.


RE: Создание скриптов с поддержкой мультиязычности - ElfbI - 22.02.2020 03:16

Тогда не пойму, где ошибся. ERA 2.8.8 Ставлю в z1 произвольный текст - все ок, пытаюсь получить перевод, пустой вопрос.
[#3/#4...] необязательно, как я понял :
В ерм:

в Mods\ElfbI Pandora\Lang\ElfbI Pandora.json
Code:
{
  "pandora90": {
    "open_box_q": "Ящик Пандоры. Вы хотите открыть ящичек?"
  }
}
И сразу вопрос, как быть с выделением текста {}


RE: Создание скриптов с поддержкой мультиязычности - Algor - 22.02.2020 03:26

!!SN:T^pandora90.open_box_q^/?z1; получаем значение ключа


(17.02.2020 15:47)Berserker Wrote:  Algor, тебе достаточно двух модов. Основного и одной локализации на английский.
...и одного для локализации на польский, и одного для локализации на китайский. Доводы понятны, механизм тоже. Хотелось бы как-то совместить в одном... подумаю еще.


RE: Создание скриптов с поддержкой мультиязычности - ElfbI - 22.02.2020 03:28

Algor, в примере
$1 - составной ключ перевода, где ключи разных уровней разделяются точками. Пример: ^bh.exp_gain_msg^

Но вы правы при этом - все заработало


RE: Создание скриптов с поддержкой мультиязычности - Algor - 22.02.2020 03:30

Ну так у тебя
ключ первого уровня = pandora90
ключ второго уровня = open_box_q
итого составной = pandora90.open_box_q
разве не так?


RE: Создание скриптов с поддержкой мультиязычности - ElfbI - 22.02.2020 03:33

Algor, это я копипастил сюда ошибся. Ключ первого уровня на самом деле был ep

Работает без первого ключа вообще. С ключом через точку - пустой вопрос.


Code:
{
  "ep": {
    "open_box_q": "Ящик Пандоры. Вы хотите открыть ящичек?"
  }
}



RE: Создание скриптов с поддержкой мультиязычности - Berserker - 22.02.2020 03:33

Символы {} можно смело использовать. Экранировать внутри строк нужно табы, переводы строк, сами двойные кавычки. \t, \n, \"


RE: Создание скриптов с поддержкой мультиязычности - ElfbI - 22.02.2020 03:37

Berserker, про экранирование - лучше написать в примере в шапке, мне кажется. Для меня термин не очень понятный. Как перевод строки экранировать, например?


RE: Создание скриптов с поддержкой мультиязычности - Algor - 22.02.2020 03:40

\n - перевод строки
\t - табулятор
\" -двойная кавычка
{ "ключ" : "первая строка\nвторая строка\n{\"желтая\" строка}" }


RE: Создание скриптов с поддержкой мультиязычности - ElfbI - 22.02.2020 03:43

Algor, Berserker, спасибо за помощь, буду пытаться)


RE: Создание скриптов с поддержкой мультиязычности - ElfbI - 22.02.2020 04:06

То, что я раньше принял за срабатывание, оказалось родным окном ящика, т к шанс на новый ящик 66%
Я пишу следующее и получаю пустой вопрос. Редактировать lua без разницы чем? Я уже не знаю, что еще.


Code:
{
  "ep": {
    "open_box_q": "{Ящик Пандоры.}\n\n Вы хотите открыть ящичек?"
  }
}



RE: Создание скриптов с поддержкой мультиязычности - Berserker - 22.02.2020 04:10

ElfbI, а мод включён? Скинь весь архив мода, пожалуйста. https://dropmefiles.com


RE: Создание скриптов с поддержкой мультиязычности - ElfbI - 22.02.2020 04:13

Berserker, https://dropmefiles.com/DHN8a

Berserker, все должно быть ок. Я вставлял тестовое сообщение в переменную перед выводом. Оно отображается. строчка 61 - пытаюсь получить ключ.

Блин, мне как-то неловко теперь - я хотел скрипт привести в нужное состояние перед опубликованием. Я не помню, он может ссылаться на внешний код:




RE: Создание скриптов с поддержкой мультиязычности - Berserker - 22.02.2020 05:33

ElfbI, json файл нужно редактировать и сохранять в редакторе, умеющим работать с кодировкой UTF-8. Например через Tools\Era_Editor_Sublime\sublime text.exe.
File - Save with encoding - UTF-8. У тебя кодировка Windows-1251 (кириллица). Вероятно, компонент работы с json порсто заменяет некорректные строки на пустые.

ElfbI, компонент json жутко молчаливый на ошибки. Даже типа не возвращает.
В Sublime Text, если используешь, ctrl + shift + p, install package, pretty json. После чего при сохранении json будут показываться ошибки. И по ctrl + alt + j.


RE: Создание скриптов с поддержкой мультиязычности - ElfbI - 22.02.2020 15:49

Berserker, спасибо, наконец-то работает. Сколько я нервов на это потратил.


RE: Ваши вопросы по ERM-скриптам - ElfbI - 06.09.2020 02:05

Можно для SN:T использовать отрицательные z?


или




RE: Ваши вопросы по ERM-скриптам - daemon_n - 06.09.2020 02:11

ElfbI, можно, но надо так
!!SN:T^jsontext.tex1^/?z-1;


RE: Ваши вопросы по ERM-скриптам - Bes - 06.09.2020 02:13

ElfbI, если верить справке (не знаю, кто там инфу готовил), то нельзя (до 2.9.14 включительно)
Quote:Все команды ERA могут работать со следующими элементами ERM:
  • Переменными y+, v, w, x, z+, f..t, e;

и нет синтаксиса set Yes
Quote:SN:T^имя^/?z#/#1/?$1/#2/?$2...



RE: Ваши вопросы по ERM-скриптам - ElfbI - 06.09.2020 02:16

Bes, daemon_n,

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


RE: Advanced Classes Mod - daemon_n - 14.09.2020 23:58

(14.09.2020 23:38)Berserker Wrote:  Переводы в json сделаны тоже модульно. Если в eng.json есть строки, которых нет в rus.json, то они будут использоваться. То есть худший сценарий — часть строк на английском, но обновлением можно пользоваться, не дожидаясь релиза локализации.

Berserker, а как ты планируешь сделать русификатор, если не перекрытием файла? Json хоть и модульный внутри, но на деле это всего лишь 1 файл.


RE: Advanced Classes Mod - Berserker - 15.09.2020 00:08

daemon_n, представь себе большой словарь вида ключ => значение, в который можно только добавлять, но не перезаписывать пары.
Первым загрузятся все ключ => значения из rus.json (более приоритетный мод).
Далее пойдут грузится пары из eng.json. Совпадающие ключи будут проигнорированы, а уникальные новые добавлены.
В результате разработчик можно сколько угодно добавлять новых ключей. Все они будут работать на оригинальном языке.

Если же ты назвал оба файла json одинаково, то будет полностью перекрыт сам файл. Это значит, что английская версия будет полностью игнорироваться, что не позволит загружать для неё обновления без обновления русификатора.


RE: Advanced Classes Mod - daemon_n - 15.09.2020 01:15

Berserker, а как заставить читаться русский файл после английского, раз у них разные имена? К тому же ключи не только добавляются, но и изменяются. Я знаю, как работает текст в json, потому сделал свой мод с 3 разными языками. (3 разных файла)


RE: Advanced Classes Mod - Berserker - 15.09.2020 01:35

daemon_n, файлы грузятся в порядке приоритетов модов. Русский загрузится раньше английского всегда и первым займёт нужные ключи.

Пример:
rus.json
hero_name = оррин
mage_power = превращение в козла

eng.json
hero_name = Zan'Zarrak
mage_power = turns into goat
welcome_message = Greetings, @hero@

Итоговый словарь в памяти игры:
hero_name = оррин
mage_power = превращение в козла
welcome_message = Greetings, @hero@


RE: Создание скриптов с поддержкой мультиязычности - Bes - 06.11.2020 00:41

(01.12.2017 23:26)Berserker Wrote:     я пишу так:
Попутно создаю Lang\test.json с содержимым:
Code:
{
  "hero_is_x_age": "@hero@ достиг @age@ лет"
}

Выводится: «Berserer достиг 27 лет» Ab

Из каких элементов состоит локализация:
1) Автоматическая подгрузка языковых json-файлов формата { "глобальный уникальный ключ": "перевод", ... }
2) Совпадающие строки из разных модов подчиняются приоритетам модов (последний установленный весомее)
3) Перевод по ключу можно загрузить из ЕРМ или плагина.
4) В перевод можно передать до 7 именованных параметров (плагинам — неограниченно), которые будут подставлены в перевод при необходимости.
@имя параметра@
5) SN:T(ключ)/?(z-переменная)/(параметр 1)/(значение 1)/(параметр N)/(значение N);
Команда получает перевод строки или возвращает сам ключ, если перевод не найден.

Berserker, в последствии ограничение в 7 параметров осталось для ERA2 ?


RE: Создание скриптов с поддержкой мультиязычности - Berserker - 06.11.2020 01:24

Bes, осталось ограничение на 16 параметров для ЕРМ команд. Как ты понимаешь, 2 + 7 * 2 = 16. То есть да.


RE: Разные вопросы - Elmore - 05.06.2021 23:21

(05.06.2021 01:20)Elmore Wrote:  Как вы делаете переводы своих модов? Вопрос к тем, кто не пишет перевод самостоятельно, а пользуется переводчиком.

Можно сделать такую схему:
- Все тексты выносить в отдельный файл и оформлять по единому шаблону. Например в ini с минимум лишнего или типа того.
- В программе указать файл для перевода и файл для сохранения текста. Подходит для любых языков.
- Программой автоматом пройтись по файлу, по очереди брать каждую строку, кидать в браузере на translate.google.com и записывать в новый файл с таким же шаблоном.

google api бесплатное не в счет, там нет ИИ алгоритмов при переводе. Только в платной версии.

Berserker, увидел json из ACM. Ну суть та же. Если все будут использовать единый метод, прога возьмет весь текст и прогонит через переводчик (в ней как раз используется js и nodejs).
Я себе для другой задачи сделал, может смогу и для героев сделать. Сложно сказать, т.к. вижу код вместе с текстом используется и он не всегда даже выделен какими-то спец символами, но вроде гугл такое не переводит. Только вот там распространяемый архив будет небольшой, а для запуска автоматически скачает полноценный браузер ~700мб.
Либо же должно "что-то" еще произойти, чтобы все новые моды хранили тексты только в json (а еще лучше в специальной папке "languages/lang_name" и менять язык где-то в файле-конфиге). Это даст возможность, хоть и не идеально, но получить мультиязычность модов.


RE: Разные вопросы - Berserker - 06.06.2021 00:29

Естественно нужно экранировать параметры. @...@ — имя параметра, его нужно до перевода заменить на что-либо, что переводчики оставляют нетронутыми, например [1], а затем вернуть назад. Кода в json нет.


RE: Разные вопросы - Elmore - 06.06.2021 01:07

{~%Z6}%Z5%Z-7 Fire Shield{~}
Вот с таким сложнее. Там может еще что-то быть, кроме {}, @@, % ?


RE: Разные вопросы - Berserker - 06.06.2021 01:57

Точно, цветные тексты.
-) {~.....}, включая {~}
-) %что-то, где %% — просто процент.
-) @...@
-) {текст} — это выделенный текст. При желании можно открывающую и закрывающую скобки рискнуть тоже обернуть. Зависит от того, портит ли их переводчик.
Это старый код, в новых проектах подставление ЕРМ 1 переменных через %... не рекомендуется категорически, но АСМ был написан до Эры 3.

{~%Z6}%Z5%Z-7 Fire Shield{~}
=>
[1][2][3] Fire Shield[4]
=>
[1][2][3] Огненный щит[4]


RE: Разные вопросы - Elmore - 06.06.2021 02:17

Сложность в определении нужного. В данном случае текст из 2х слов и получается:
[{~%Z6}][%Z5%Z-7] [Fire Shield][{~}]
от % до пробела, если не %%
Но пока думаю, как определять процент в середине слова и как обрабатывать... остальное легко.
Такая ситуация "{}%что-то" или "%что-то{}" слитно может быть где-то, кроме начала и конца строки?


RE: Разные вопросы - Berserker - 06.06.2021 02:53

Это регулярные выражения или разбор на лету по токенам, как удобнее. Может быть что угодно.
По процентам регулярка вида: /(%[A-Za-z]\-?\d*+)/
Там латинская буква + опциональное число.


RE: Разные вопросы - Elmore - 11.06.2021 15:11

Berserker, в json возможна ситуация кроме key.key.value ?


RE: Разные вопросы - Berserker - 11.06.2021 16:25

Elmore, в переводных json могут быть объекты любой вложенности, которые заканчиваются парой ключ: строка

{ "a": { "b": { "c": "value"

Они преобразуются в плоскую карту вида "a.b.c.d": "value" самой Эрой. Ключи вида "a.b.c.d" тоже поддерживаются.


RE: Разные вопросы - Elmore - 11.06.2021 17:33

Понял, значит будет проверять чуть больше.


RE: Ваши вопросы по ERM-скриптам - Archer30 - 03.04.2022 13:33

I have a bit of difficulty working on non-ascii characters (») with JSON, it doesn't seem to have any way to be shown in the game correctlyy.

Screenshot:
Image: fCY0Mmj.png

The » symbol is both in my ert and json. The one from ert was displayed correctly (blue), while the one from json was just displayed as ? (red).

json:
Code:
{
    "es":{
        "747":{
            "basicDesc": "\n{»} {10%} of unused movement points convert to experience points.  ",
            "advancedDesc": "\n{»} {20%} of unused movement points convert to experience points.    ",
            "expertDesc": "\n{»} {30%} of unused movement points convert to experience points."
        }
    }
}

erm:

I wonder if there is a way to solve it for json, otherwise I may have to do a mix of json +ert. Sorry


RE: Ваши вопросы по ERM-скриптам - Berserker - 03.04.2022 17:48

No way. Json data is in UTF-8. It's transformed into ANSI (system code page) on load. Most unicode characters are lost during such transformation, except those, which are present in system ANSI encoding. Afterwards those ANSI characters (single byte for Russian/English/Polish and multi-byte for Chinese) are displayed using fnt font.


RE: Ваши вопросы по ERM-скриптам - Archer30 - 03.04.2022 17:51

Berserker, thanks for the answer! 132


RE: Ваши вопросы по ERM-скриптам - wessonsm - 03.04.2022 17:59

Hmm. I just tried it and I have this symbol » normally displayed with json from the post above.
Is it because I have Cyrillic windows?


RE: Ваши вопросы по ERM-скриптам - Archer30 - 03.04.2022 22:36

wessonsm, thanks for testing!

I tested with daemon_n with the same json file, and we've achieved different results. It worked well for him, but not me. For now, I can only conclude the problem is PC specific.


RE: Ваши вопросы по ERM-скриптам - Berserker - 04.04.2022 06:05

wessonsm, right, because Windows-1251 Encoding has this symbol and russian fnt file also has it. Chinese encoding does not include it.


RE: Создание скриптов с поддержкой мультиязычности - wessonsm - 25.02.2023 20:02

У меня в json несколько ключей с именами типа "wss.defname1", "wss.defname2", "wss.defname3" и так далее.
Как мне прочитать их значения в цикле и записать в массив?
Если я пытаюсь получить имя ключа так:
sprintf(Key[i], "wss.defname%d", i);
defname[i] = tr(Key[i]);
у меня не получается тип const char*, который требует функция tr.


RE: Создание скриптов с поддержкой мультиязычности - daemon_n - 26.02.2023 08:14

wessonsm, что за тип Key[i] ?
если это массив std::string , то вызови метод c_str() -> Key[i].c_str();

в общем, я думаю, у тебя что-то такое:
Code:
std::vector<std::string> Key;
std::vector<std::string> defname;
...
int i = 0;
defname[i] = Era::tr(Key[i].c_str());



RE: Создание скриптов с поддержкой мультиязычности - wessonsm - 26.02.2023 18:14

daemon_n, да. Сделал std::string - дело пошло, кажется. У меня был обычный массив char[].
Но появились другие проблемы, пытаюсь разбираться в общем.
С трудом мне эти json даются.
Пока все в коде плагина - все работает, как только пытаюсь сделать загрузку параметров из json - все ломается.


RE: Создание скриптов с поддержкой мультиязычности - XEPOMAHT - 26.02.2023 20:23

(25.02.2023 20:02)wessonsm Wrote:  У меня в json несколько ключей с именами типа "wss.defname1", "wss.defname2", "wss.defname3" и так далее.
Как мне прочитать их значения в цикле и записать в массив?
Если я пытаюсь получить имя ключа так:
sprintf(Key[i], "wss.defname%d", i);
defname[i] = tr(Key[i]);
у меня не получается тип const char*, который требует функция tr.

Проще создать и обрабатывать в цикле заранее подготовленный массив строк, т.е. имена "wss.defname1", "wss.defname2", "wss.defname3" и так далее записать компилятором непосредственно в саму программу в виде dword. Получение строк из json и так работает не очень быстро, а обработка "sprintf(Key[i], "wss.defname%d", i);" замедлит загрузку строк из json ещё сильнее.

(26.02.2023 18:14)wessonsm Wrote:  С трудом мне эти json даются.
Пока все в коде плагина - все работает, как только пытаюсь сделать загрузку параметров из json - все ломается.

Не мучайся и подгружай обычный txt. Лично у меня в ERA+ json не используются как раз по причине их сложности: не могу сделать их загрузку в память программы и в блокноте создавать сам json - писец какой-то из-за многочисленных фигурных скобочек, в которых я постоянно ошибаюсь....


RE: Создание скриптов с поддержкой мультиязычности - wessonsm - 26.02.2023 20:51

(26.02.2023 20:23)XEPOMAHT Wrote:  Не мучайся и подгружай обычный txt. Лично у меня в ERA+ json не используются как раз по причине их сложности: не могу сделать их загрузку в память программы и в блокноте создавать сам json - писец какой-то из-за многочисленных фигурных скобочек, в которых я постоянно ошибаюсь....
Возможно, я так и сделаю.
Но все же текстовые таблицы не годятся для локализаций на азиатские языки, например. А там у меня и хинт-текст должен быть, который я тоже в json засунуть планировал.
Хочется сделать по-человечески. Да и вообще разобраться, что я не так делаю.
И до меня только что дошло, что sprintf используется для однобайтовых кодировок, а в json там многобайтовая. Возможно в этом проблема?


RE: Создание скриптов с поддержкой мультиязычности - Berserker - 27.02.2023 06:25

Quote:Получение строк из json и так работает не очень быстро
Максимально быстро. По готовому ключу в словаре, реализованному как быстрая хэш-карта.

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


RE: Создание скриптов с поддержкой мультиязычности - igrik - 27.02.2023 10:55

wessonsm, возьми за образец мой способ копирования всех строк json в диалоге WoG Опций из WND.


RE: Создание скриптов с поддержкой мультиязычности - wessonsm - 28.02.2023 01:46

Огромное спасибо всем за желание помочь.
Я хочу сделать примерно вот такие кнопочки для карты приключений, которые нельзя сделать с помощью buttons.dll:
Image: buttons.png
Ну в целом я их сделал наполовину, кнопочки видны и нажимаются, нажатия отслеживаются из erm, позиция автоматически подстраивается под разрешение HD-мода. Осталось сделать отображение хинт-текста и смену кадра курсора при наведении на кнопки (с чем я надеюсь справиться). Плюс они не перекрашиваются в цвета игрока, но это уже другая проблема.
И загрузку параметров из json, над чем бьюсь безрезультатно третий день.

Вот этот код работает: (Click to View)
Вот мой json: (Click to View)

Проблема, как оказалось, не в циклах, а в том, что я вообще не могу прочитать ни одного параметра из json.
С json у меня не заладилось с самого начала.
Началось все с того, что компилятор visual studio 2008 ругался на объявление функции tr из era.h
std::string tr (const char *key, std::vector<std::string> params = {})
Сейчас у меня visual studio 2010, он тоже ругается.
Я убрал тогда ={} и на этом успокоился, компилятор ругаться перестал, и все работало до тех пор, пока я не пытался вызывать функцию tr.
Поскольку подставляемых параметров у меня в json нет, мне нужно передать в функцию пустой вектор из 0 элементов. Как это сделать, я понятия не имею и поэтому прошу помощи.
Я даже не хочу постить весь тот бред сивой кобылы, который я пытался писать.
В итоге если компилятор каким-то чудом это принимал, либо я получал ошибку загрузки dll, либо функция возвращает имя параметра вместо его значения, либо вылет.
Может, как-то можно туда все таки передать этот пустой вектор, а может, мне нужно переделать саму функцию tr, если кто-то подскажет, буду весьма благодарен.


RE: Создание скриптов с поддержкой мультиязычности - XEPOMAHT - 28.02.2023 02:48

(28.02.2023 01:46)wessonsm Wrote:  Я хочу сделать примерно вот такие кнопочки для карты приключений, которые нельзя сделать с помощью buttons.dll:
Image: buttons.png

Да можно, только потребуется перекомпиляция buttons.dll, т.к. этот старый плагин был написан до HD-мода и часть его функционала HD-мод просто не даёт исполнять (т.к. Бараторч очень любит перехватывать функции целиком увы, что приходится обходить различными обходными манёврами в коде или просто костылями). Например Тифон 3 перехватывает почти весь функционал buttons.dll и заставляет его выполняться вместе с HD-модом, НО!!! Эровские конфиги при этом не работают, т.к. это вообще только Берсеркеру известно как нужно читать данные из памяти era.dll - мне никак не разобраться в секретах передачи данных между эрой и плагинами к ней, ну, если они вообще нужны, можно их читать из обычного текстовика, без каких-либо извращений. А так, если без конфигов - всё на уровне исполняемого кода (по крайней мере в Тифоне мне так удобнее).

(28.02.2023 01:46)wessonsm Wrote:  Ну в целом я их сделал наполовину, кнопочки видны и нажимаются, нажатия отслеживаются из erm, позиция автоматически подстраивается под разрешение HD-мода. Осталось сделать отображение хинт-текста и смену кадра курсора при наведении на кнопки (с чем я надеюсь справиться). Плюс они не перекрашиваются в цвета игрока, но это уже другая проблема.
И загрузку параметров из json, над чем бьюсь безрезультатно третий день.

Ну если напишешь плагин, полностью заменяющий устаревший buttons.dll, то в среде моддеров он наверняка найдёт применение (да и Берсеркер может включить его в саму ЭРУ, удалив наконец-то наследие Феникс-мода). То, что тебе осталось сделать, присутствует в buttons.dll (исходники у Маячка на сервере вроде б лежали, если нужны, но там чистый Ассемблер, под СИ не покатит точно, ну и добавится несовместимость с ЭРА+ при этом, т.к. адреса лучше брать у Игрика - так надёжнее).


RE: Создание скриптов с поддержкой мультиязычности - igrik - 28.02.2023 03:21

wessonsm, с JSON очень легко работать. Когда у тебя получится - ты это оценишь.

Вот выдержка из моего кода (я тоже писал WND на VS 2008)
Code:
// изменённая фукнция в era.h для работы с VS2008
char* tr (const char *key) {
  char* buf = _tr(key, NULL, -1);
  char* result = ToStaticStr(buf);
  MemFree(buf);

  return result;
}


// функция получения JSON строк методом ERA (в главном файле WND)
char* GetEraJSON(const char* json_string_name) {
    return tr(json_string_name);
}


// код из WND
char strPage[1024];
char* textPage = "wog_options.page%d.%s";

sprintf(o_TextBuffer, textPage, 42, "key_name");

// ... или ... получаем структуру диалога ВОГ Опций
_DlgSetup_* ds = o_WogOptions;
SetupJsonText(&ds->Name, "wog_options.main.name");

// ... или ... другая строка (в цикле: i = итератор)
sprintf(strPage, textPage, i, "key_name");
SetupJsonText(&ds->Pages[i]->Name, strPage);

PS: вечером постараюсь помочь с твоим кодом (для этого скинь ресурсы кнопок и бэкграунда)


RE: Создание скриптов с поддержкой мультиязычности - wessonsm - 28.02.2023 04:54

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

igrik, большое спасибо за функцию, опробую в ближайшее время, как только смогу.
Кнопки и pcx я слепил на скорую руку из того что было, просто чтобы опробовать работоспособность плагина:
https://dropmefiles.com/4tzGH


RE: Создание скриптов с поддержкой мультиязычности - igrik - 01.03.2023 20:09

wessonsm, держи
Code:
#include "stdafx.h"
#include "..\..\include\homm3.h"
#include "..\..\include\era.h"

using namespace Era;

Patcher* _P;
PatcherInstance* _PI;

///////////////////////////////////////////////////////////////////

class Background {
  public:
    int id;
    int x;
    int y;    
    std::string pcxname;
};

class Button {
  public:    
    int id;
    int x;
    int y;    
    int caption_color;
    std::string defname;
    std::string caption_font;
    std::string caption_text;
    std::string popup_text;
    std::string hint_text;
};

class Namb {
  public:
    int qty;
    int align;
    Background *background;
    Button *buttons;

  Namb (int qty, int align) {
    this->qty = qty;
    this->align = align;
    this->background = new Background;
    this->buttons = new Button[qty];
  }

  ~Namb() {
    delete background;
    delete[] buttons;
  }
};

Namb *namb = NULL;

///////////////////////////////////////////////////////////////////

char* GetJsonStr(const char* json_string_name) {
    return tr(json_string_name);
}

int GetJsonInt(const char* json_string_name) {
    return atoi(GetJsonStr(json_string_name));
}

char* GetButtonsParamStr(int i, const char* key) {    
    sprintf(o_TextBuffer, "namb.button%d.%s", i, key);
    return GetJsonStr(o_TextBuffer);
}

int GetButtonsParamInt(int i, const char* key) {
    sprintf(o_TextBuffer, "namb.button%d.%s", i, key);
    return GetJsonInt(o_TextBuffer);
}

///////////////////////////////////////////////////////////////////
    
// функция загрузки параметров из json
int __stdcall ReadJsonConfig()
{    
    int qty = GetJsonInt("namb.qty");
    int align = GetJsonInt("namb.align");

    namb = new Namb(qty, align);

    namb->background->pcxname = GetJsonStr("namb.background.pcxname");
    namb->background->id = GetJsonInt("namb.background.id");
    namb->background->x = GetJsonInt("namb.background.x");
    namb->background->y = GetJsonInt("namb.background.y");

    for(int i = 0; i < qty; i++) {
        namb->buttons[i].id = GetButtonsParamInt(i, "id");
        namb->buttons[i].x = GetButtonsParamInt(i, "x");
        namb->buttons[i].y = GetButtonsParamInt(i, "y");
        namb->buttons[i].caption_color = GetButtonsParamInt(i, "caption_color");

        namb->buttons[i].defname = GetButtonsParamStr(i, "defname");
        namb->buttons[i].caption_font = GetButtonsParamStr(i, "caption_font");
        namb->buttons[i].caption_text = GetButtonsParamStr(i, "caption_text");
        namb->buttons[i].popup_text = GetButtonsParamStr(i, "popup_text");
        namb->buttons[i].hint_text = GetButtonsParamStr(i, "hint_text");
    }

    return 1;
}

///////////////////////////////////////////////////////////////////

_Dlg_* __stdcall hook_AdvMapDlg_Construct(HiHook* hook, _Dlg_* dlg)
{
    int HDResX, HDResY, offsetx, offsety, x, y, id, color;
    char *name, *caption, *font;
    
//    HDResX = *(int*)0x4F81BC;    HDResY = *(int*)0x4F81C3;
    HDResX = o_WndMgr->screen_pcx16->width;
    HDResY = o_WndMgr->screen_pcx16->height;
    switch (namb->align)    {
        case 0:        
            offsetx = 0;
            break;

        case 2:        
            offsetx = HDResX - 800;
            break;

        case 1:        
        default:
            offsetx = (HDResX - 800)/2;
            break;                
    }    
    offsety = HDResY - 600;

    CALL_1(_Dlg_*, __thiscall, hook->GetDefaultFunc(), dlg);

    x = namb->background->x;
    y = namb->background->y;
    id = namb->background->id;
    name = (char*)(namb->background->pcxname.c_str());
    
    dlg->AddItem(_DlgStaticPcx8_::Create(x + offsetx, y + offsety, id, name) );

    for (int i=0; i < namb->qty; i++)    {
        x = namb->buttons[i].x;
        y = namb->buttons[i].y;
        id = namb->buttons[i].id;
        color = namb->buttons[i].caption_color;

        name = (char*)(namb->buttons[i].defname.c_str());
        caption = (char*)(namb->buttons[i].caption_text.c_str());
        font = (char*)(namb->buttons[i].caption_font.c_str());
        
        _DlgTextButton_* bttn = _DlgTextButton_::Create(x + offsetx, y + offsety, id, name, caption, font, 0, 1, 0, 0, color);
            bttn->short_tip_text = (char*)(namb->buttons[i].caption_text.c_str());
            bttn->full_tip_text = (char*)(namb->buttons[i].popup_text.c_str());
        dlg->AddItem(bttn);
    }
    return dlg;    
}



int __stdcall hook_BeforeDrawAgems(HiHook* hook, _AdvMgr_* pAdvManager)
{
    _Dlg_* pDlgAdvMap;
    _DlgItem_* pItem;

    pDlgAdvMap = pAdvManager->dlg;

    pItem = pDlgAdvMap->GetItem(namb->background->id);
    pItem->Draw();

    for (int i = 0; i < namb->qty; i++) {
        pItem = pDlgAdvMap->GetItem(namb->buttons[i].id);
        pItem->Draw();
    }

    return CALL_1(int, __thiscall, hook->GetDefaultFunc(), pAdvManager);
}

_LHF_(LoHook_InitTxtFiles)
{
    ReadJsonConfig();
    return EXEC_DEFAULT;
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{
    static _bool_ plugin_On = 0;

    if ( (ul_reason_for_call==DLL_PROCESS_ATTACH) && (!plugin_On) ) {
        plugin_On = 1;
        _P = GetPatcher();
        _PI = _P->CreateInstance("new_buttons");
        ConnectEra();
        _PI->WriteLoHook(0x4EEAC0, LoHook_InitTxtFiles);
        _PI->WriteHiHook(0x401510, SPLICE_, EXTENDED_, THISCALL_, hook_AdvMapDlg_Construct);
        _PI->WriteHiHook(0x40F250, SPLICE_, EXTENDED_, THISCALL_, hook_BeforeDrawAgems);
    }
    return TRUE;
}



RE: Создание скриптов с поддержкой мультиязычности - wessonsm - 02.03.2023 06:05

igrik, Спасибо тебе огромное!
Если что-то не получится, спрошу еще 145

Всё работает, остались мелочи.
Ты не представляешь, сколько времени и нервов ты мне сэкономил!

119119119


RE: Создание скриптов с поддержкой мультиязычности - wessonsm - 10.03.2023 02:52

Berserker,
Возвращаясь к этим кнопкам.
Благодаря igrik'у меня все заработало, хинт и описание по правому клику я тоже доделал; и да, я уже умею передать в функцию пустой вектор ))
По сути мой плагин готов.
И возник следующий вопрос, сложнее Sm

Допустим, я хочу, чтобы у меня в json
вместо "button0", "button1", "button2" и так далее были уникальные имена кнопок
типа "map", "market", "hero" и тому подобные.
То есть у меня будут ключи вида
"XXX.map.ZZZ"
"XXX.market.ZZZ"
"XXX.hero.ZZZ",
но я не знаю заранее, сколько их будет и какими они будут (что там будет вместо "map", "market", "hero").
Можно ли найти и прочитать все существующие ключи такого вида?
Функции tr для этого недостаточно, нужен другой инструмент.
Если я правильно думаю, что весь набор ключей из различных json представляет собой один упорядоченный ассоциативный массив,
то для этого должен использоваться также поиск в ассоциативном массиве, как и при чтении единичного ключа, ну то есть теоретически это возможно.
Или это неупорядоченный ассоциативный массив на основе хэша? (есть основания это предполагать)
Можно такое провернуть и сложно ли будет это сделать?
Для меня это очень актуально, так как кроме этих кнопок, у меня есть еще пара-тройка мыслей, где можно такой подход использовать.


RE: Создание скриптов с поддержкой мультиязычности - Berserker - 10.03.2023 07:23

Скажем так, tr действительно простой инструмент. Всего функционала навигации по json он не предоставляет. Тут либо использовать библиотеку парсинга json на С++, либо поступить хитрее. "namb" будет массивом кнопок, а не объектом. А у каждой кнопки будет поле "name" или "key" или "id".
Тогда ты в цикле считываешь namb.[индекс].id, пока не получишь в качестве значения сам текст ключа, что говорит об отсутствии значения.