## Documentation Localization Some documentation for stumpless has localization available. This is completely community supported, and the amount of translations available for different locales varies widely. To see the documentation for a given language, check the `l10n` folder in the root of the repository. There are folders for locales with translations available. These are structured as a mirror of the root of the repository, with documents with no localization missing. Note that some files may only have partial translations available. File and folder names may be localized as well, though this is not strictly required. If you would like to contribute localization of part or all of a file, you only need to submit a pull request with the changes made. Keep in mind that only requests with a substantial addition will be added. For example, an update that simply adds a filename with no contents or only a few sentences will not be accepted. ## Library Localization Stumpless implements a simple framework to support different languages for human-readable output, such as error messages. This implementation is based on the use of header files with definitions for the strings based on a specific locale. A simple wrapper header, `private/config/wrapper/locale.h`, can then be included by source files. This wrapper header chooses the correct locale header based on the build configuration. ## Locale Headers Locale headers are located in `private/config/locale` and are named after the locale that they hold using the IETF Language Tag format defined in [RFC 5646](https://tools.ietf.org/html/rfc5646). For example, the United States English locale is in `private/config/locale/en-us.h`. These header files all define the same set of preprocessor symbols, each beginning with the prefix `L10N_`. These are string constants that will be placed into the source code during compilation to customize the library for the desired locale. Some of these symbols may be functions that take string constants as parameters and insert these into the appropriate location. An example of this is the `L10N_NULL_ARG_ERROR_MESSAGE` function, which takes the name of the argument that was null as a parameter so that it can insert it into the error message. Different locales may use this value in different places, or not at all. ## Adding New Strings If you are making a change that requires a new error message or other string that needs to be localized, you will need to add it to all defined locales. It is _required_ that the `en-us` locale include a meaningful definition of the symbol. Others may be added as a placeholder value, for later translation by someone with the necessary knowledge. For any string that is not translated, a comment of `// todo translate` must be added before the definition, and the value of the string must be equal to the `en-us` value as a fallback. The `scripts/check_l10n.rb` script can check this, and is run during integration tests on all headers. The `scripts/add_l10n_scripts.rb` provides a quick way to do all of this for new strings. Run it with the name of the new string and the english translation, and it will insert placeholders into all locale headers. Here's an example invocation: ```sh # this will result in a string of L10N_TEST_STR being added to all locale # headers with the english translation of "this is a test string" ruby scripts/add_l10n_scripts.rb TEST_STR this is a test string ``` ## Finding Strings to Translate Strings that need to be translated are marked with a `// todo translate` comment in the localization headers. This means that you can easily find how many strings need to be translated in any locale, despite stumpless not currently having any integrations with translation frameworks. The following grep invocation will give a count of how many untranslated strings exist: ```sh grep -r -c "// todo translate" include/private/config/locale/ # output looks like this: # include/private/config/locale/bg-bg.h:12 # include/private/config/locale/cz-cz.h:1 # include/private/config/locale/de-de.h:20 # include/private/config/locale/el-gr.h:0 # include/private/config/locale/en-us.h:0 # include/private/config/locale/es-es.h:2 # include/private/config/locale/fr-fr.h:20 # include/private/config/locale/it-it.h:0 # include/private/config/locale/pl-pl.h:1 # include/private/config/locale/sk-sk.h:17 # include/private/config/locale/sv-se.h:20 ``` ## Defining a New Locale Adding a new locale to the library only requires the addition of the new header file and making sure that it can be used during build configuration. Adding the header is straightforward: just copy any already existing header (this will be easier if you understand the language of the original) and then change the defined symbols to reflect your new locale. Be sure that the name of the new header is a valid IETF Language Tag in all lowercase letters. After adding the header itself, you will need to tie it in to the build system by updating the `tools/cmake/l10n.cmake` file, the `include/private/config.h.in` header template, and the locale wrapper `include/private/config/wrapper/locale.h`. In the CMake script, add an `elseif` block to the chain of conditionals responsible for determining the locale following the pattern of the others that are already there. Next, in the private config header template, add a definition for the locale symbol for the new locale. This symbol should be of the form `USE_LOCALE_XXX` where the last portion is the RFC 5646 language tag in all caps with underscore separators. Again, reference the already defined locales to see what this should look like. Finally, in the locale wrapper header add an `#elseif` statement for the new locale symbol in the same order as it appears in the CMake build script to include the new header. The last step is to add new CI builds for the new locale to make sure that there are no immediate problems and catch any future ones that arise. This is done by updating the `.github/workflows/locale.yml` configuration file with a build profile for the new language. This is relatively simple: just copy one of the existing jobs (for example `linux-es-es`) and update it to use your new locale. Finally, add a flag for the new locale to the project README (in the Key Features section) to show off your hard work to everyone else!