Code View

mstring

mstring

mstring (message-string) generates C++ code from a file of localized messages. You write each message once — its parameters and its text in every language — and mstring writes the functions and classes that produce it: a string function, a streamable class, an error function, an exception class with a throw function, a syslog function. The generated code needs nothing but the C++17 standard library.

$MODULE hello
$STRING ENABLE
$LANGUAGE en

$MESSAGE Welcome
@ user std::string const &
"Welcome, {$user}!"
[tr]
"Hoş geldin, {$user}!"
mstring hello.msg        # → hello.hh, hello.cpp
#include "hello.hh"

std::cout << WelcomeStr( "Ada" );                              // Welcome, Ada!
std::cout << WelcomeStr( "Ada", std::locale( "tr_TR.UTF-8" ) ); // Hoş geldin, Ada!

The language is chosen from the locale name at run time ([tr] matches tr_TR.UTF-8); the texts are compiled in, there are no catalog files to ship.

What it is for. mstring is at its best for the messages of C++ libraries and tools: errors, exceptions, log lines and diagnostics in a few languages, with typed parameters (a wrong argument is a compile error, not a garbled message at run time) and no runtime dependency. It is not a general UI translation system: translations are compiled in (a new translation means a rebuild), and there are no plural rules yet — for an application's user interface, gettext, ICU or your framework's catalog system fit better.

  • mstring.fedem.eu — the documentation site: user guide, the language with railroad diagrams, reference manual, annotated examples.
  • docs/syntax.md — the message file language, what is generated, the command line.
  • examples/ — hello (languages, formats, string and streamable) and errors (exception, throw, fatal error, syslog), each built and smoke-tested with the project.

Building

The parser is built on cparse; the build takes it from Conan.

conan build .                      # configure, build, run the tests
conan create .                     # package it into the local Conan cache

or, for development:

conan install . --build=missing
cmake --preset conan-release
cmake --build --preset conan-release
ctest --test-dir build/Release --output-on-failure

CMake options: TESTING (tests/, default ON), EXAMPLE (examples/, default ON). The tests compile the code mstring generates for every feature with -Wall -Wextra -Wpedantic -Werror and run it, and check the diagnostics of broken inputs.

Using mstring from CMake

mstring_generate() (cmake/mstring-generate.cmake, installed to lib/cmake/mstring/) runs mstring at build time:

mstring_generate(MESSAGES_GENERATED messages.msg)      # → messages.hh / .cpp
add_executable(app main.cpp ${MESSAGES_GENERATED})
target_include_directories(app PRIVATE ${CMAKE_CURRENT_BINARY_DIR})

Options: MODULE, OUTPUT_DIRECTORY, HEADER_EXTENSION, SOURCE_EXTENSION, NOHEADER, NOSOURCE, INLINE, IMPORT_DIRECTORIES, OPTIONS (extra mstring options, e.g. -w), DEPENDS (list the $IMPORTed files there) — see the comment at the top of the file.

From a Conan consumer, take mstring as a tool and let CMakeDeps bring the module in:

def build_requirements(self):
    self.tool_requires("mstring/[>=1.1 <2]")

def generate(self):
    deps = CMakeDeps(self)
    deps.build_context_activated = ["mstring"]
    deps.build_context_build_modules = ["mstring"]
    deps.generate()
find_package(mstring REQUIRED)   # defines mstring_generate()

Layout

Path
src/MStringParser.*the message-file grammar (a cparse Parser)
src/Settings.*, src/Message.*, src/Module.hhwhat the parser builds
src/MMessage.*, src/MText.*, src/MParameter.*, …the C++ writers
src/MString.*, src/main.cppoutput files, command line
cmake/mstring-generate.cmakemstring_generate()
tests/feature, import, NOHEADER, INLINE, stdin, warning and diagnostics tests
examples/the examples
bench/ns per call of the generated string functions (-DBENCH=ON)

License

MIT — see LICENSE, CONTRIBUTING.md and TRADEMARKS.md.