Миллион лет назад, я первый раз попытался использовать штатный механизм управления строковыми ресурсами в Visual Studio: был травмирован, зол и разочарован. С тех пор я видел много иных инструментов для той же задачи, но время как будто остановилось - не меняется ничего. И потому очень рад, что тогда давно сделал собственный инструмент и десятилетия работаю с ним. Кратко расскажу обо всем этом.

Итак, это небольшой компилятор, транслирующий описание ресурсов в бинарное представление, которое используется собственно приложением. Технически, кстати, это - open-source, но находится внутри большого репозитория как инструментальный компонент.

Что он умеет:

  • Идентификация по целочисленному ключу, заданному с помощью мнемоники. Эта мнемоника транслируется компилятором опять же в целочисленное значение. Что-то вроде такого:
    ERR_FILENOTFOUND "Файл не найден"

  • Идентификация строк по явно заданному целочисленному ключу. Скажем, так:
    924 "Ошибка компонента супер-библиотека: ничего не могу сделать"
    Здесь, видимо, потребуется уточнение зачем такой, прямой как рельса, способ идентификации. Главная причина - внешние компоненты приложения. Вот смотрите, когда мы действуем в зоне ответственности основного приложения, то мнемоническая идентификация отлично работает. Но если у нас есть некая внешняя библиотека, которая поставляет кодировку ошибок и других текстов с явной привязкой к значению, то нам придется расписывать строки именно с такой привязкой.

  • Идентификация строк по символьному ключу (просто короткая строка). Например:
    @chzn "честный знак"

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

  • Умеет разбивать строки по категориям. Ошибки - здесь, сообщения - там, заголовки диалоговых форм - тут.

  • Кроме упомянутых пунктов, для большого проекта бывают нужны специальные группы строк, формирующие внутри приложения хэш-таблицы. Зачем это может понадобиться? Например, для разбора и формирования xml- и json-данных. То есть, текстовые наименования тегов и атрибутов определяем в ресурсе, а внутри программы оперируем целочисленными константами.
    Это особенно удобно если вы вынужденны работать с тегами в национальном алфавите (nalog.ru и 1с-совместимо, привет!).
    В программном коде держать такие строки тоскливо из-за того, что надо помнить в какой кодировке исходный файл.

  • Кроме относительно коротких строк, он умеет работать с длинными текстовыми дополнениями.
    Как то так:

@someswitch "Переключатель какой-то"
	#{
		На самом деле, это - очень важный переключатель. Если вы его переключите, то все пойдет наперекосяк!
	#}
  • Файл строкового ресурса надо переводить на другие языки частью в автоматическом, частью - в ручном режимах. Так как не все строки должны подвергаться переводу, то применяются вспомогательные директивы, позволяющие пропустить перевод одного или нескольких строковых объекта.

  • Ну и, само собой, комментарии обязательны.

	PPHSC_VETIS_DOCTYP_14 "Ветеринарный сертификат РФ на вывоз продукции на территорию стран ТС" // Текст не менять - точное соответствие!
  • А еще есть опция, позволяющая в определении строк ссылаться на другие строки в этом же ресурсе. Вот пример (строка с символом @rejected определена где-то в этом же файле):

	@styloqdocstatus_fbillflagdeclined "Использовать признак документа '@{rejected}'"
  • Есть еще нетривиальная фича: скомпилировать этот ресурс в бинарный файл и использовать результат в разных проектах. На c++, java и может еще каких-то. Мы применяем эту возможность чтобы не плодить дублируемые сущности для разных проектов. В том числе для Android.

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

Пример файла описания

Пример, разумеется, игрушечный. Реальный модуль содержит почти 20 тысяч строк.

[1]
PPERR_INVNFPARAMBUF                "@{err_internal}: недопустимый размер буфера параметров пакетного задания"
PPERR_CMDSEL_EXP_SELECT            "@{err_incmd}: ожидается SELECT"
PPERR_CMDSEL_EXP_OBJTYPE           "@{err_incmd}: ожидается тип объекта"
PPERR_CMDSEL_EXP_BY                "@{err_incmd}: ожидается BY"
PPERR_CMDSEL_EXP_CRITERION         "@{err_incmd}: ожидается критерий"

[2]
PPTXT_TODO_PRIOR                          "1,@{todoprior_highest};2,@{todoprior_high};3,@{todoprior_normal};4,@{todoprior_low};5,@{todoprior_lowest}"
PPTXT_LOG_UNEQTRFRBILLDATE                "Дата строки документа не соответствует дате документа (%s)"

[25]
700  /!/ "AMQP error: Unknown AMQP error (%s)"
701  /!/ "AMQP error: Incorrect or corrupt data was received from the broker. This is a protocol error (%s)"

[100]
@position_left                       "Слева"
@position_right                      "Справа"
@direction_left                      "Налево"
@direction_right                     "Направо"
@direction_up                        "Вверх"
@direction_down                      "Вниз"
@direction_forward                   "Вперед"
@direction_backward                  "Назад"
@cancelinput                         "Отмена" // В смысле UI отмена ввода

[124:hash]
#!{ // Директива "не переводи!"
PPHSC_RU_FILE                  "Файл"
PPHSC_RU_IDFILE                "ИдФайл"
PPHSC_RU_VERPROG               "ВерсПрог"
PPHSC_RU_VERFORM               "ВерсФорм"
PPHSC_RU_VERFORM2              "ВерсияФормата" // @v11.9.5 SBIS
PPHSC_RU_FORMAT                "Формат" // @v11.9.5 SBIS
PPHSC_RU_REPFORM               "ФормаОтч"
#!}

Где это все?

Как я упоминал выше, описанная техника работы с текстовыми ресурсами - часть большого проекта. Вот его адрес на: https://github.com/papyrussolution/OpenPapyrus.
Компилятор называется назамысловато: sc2c.

Вопросы, замечания, молчаливое использование - все приветствуется!