# 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}!"
```
```sh
mstring hello.msg # → hello.hh, hello.cpp
```
```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](https://mstring.fedem.eu)** — the documentation
site: user guide, the language with railroad diagrams, reference manual,
annotated examples.
- **[docs/syntax.md](docs/syntax.md)** — the message file language, what is
generated, the command line.
- **[examples/](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](https://cparse.fedem.eu); the build takes it
from Conan.
```sh
conan build . # configure, build, run the tests
conan create . # package it into the local Conan cache
```
or, for development:
```sh
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:
```cmake
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 `$IMPORT`ed 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:
```python
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()
```
```cmake
find_package(mstring REQUIRED) # defines mstring_generate()
```
## Layout
| Path | |
|---|---|
| `src/MStringParser.*` | the message-file grammar (a cparse `Parser`) |
| `src/Settings.*`, `src/Message.*`, `src/Module.hh` | what the parser builds |
| `src/MMessage.*`, `src/MText.*`, `src/MParameter.*`, … | the C++ writers |
| `src/MString.*`, `src/main.cpp` | output files, command line |
| `cmake/mstring-generate.cmake` | `mstring_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](LICENSE), [CONTRIBUTING.md](CONTRIBUTING.md) and
[TRADEMARKS.md](TRADEMARKS.md).