We deal with a variety of different displays. And we try to display a lot of different languages in different scripts on them. This system is ought to solve some of the related problems.
We have two different technologies for the displays:
At all of them you can define 8 different symbols by yourself. In Marlin they are used for the Feedrate-, Thermometer-, … symbols
For the moment Marlin wants to support a lot of languages:
and recently on Thingiverse a new port to
appeared.
All of this languages, except the English, normally use extended symbol sets, not contained in US-ASCII. Even the English translation uses some Symbols not in US-ASCII. ( ‘\002’ for Thermometer, STR_h3 for ‘³’) And worse, in the code itself symbols are used, not taking in account, on what display they are written. (This is true only for Displays with Japanese charset on Western displays you’ll see a ‘~’ and on Cyrillic an ‘arrow coming from top - pointing to left’, what is quite the opposite of what the programmer wanted.) The Germans want to use “ÄäÖöÜüß” the Finnish at least “äö”. Other European languages want to see their accents on their letters. For other scripts like Cyrillic, Japanese, Greek, Hebrew, … you have to find totally different symbol sets.
Until now the problems where ignored widely. The German translation used utf8 ‘ä’ and ‘ö’ and did not care about showing garbage on ALL displays. The Russian translators new that their system only works on the Cyrillic character displays and relied on special LCD routines (LiquidCrystalRus.cpp) to handle UTF8 but missed to implement a proper strlen(). The Japanese translator dealed with to scripts. He introduced a very special font for the full graphic displays and made use of the Japanese version of the character displays. Therefore he ended up with two pretty unreadable language.h files full of ‘\xxx’ definitions. Other languages ether tried to avoid wording with their special symbols or ignored the problem at all and used the basic symbols without the accents, dots, … whatever.
On a ‘perfect’ system like Windows or Linux we’d dig out unifont.ttf and some code from the libraries and they’d do what we want. But we are on a embedded system with very limited resources. So we had to find ways to limit the used space (Alone unifont.ttf is about 12MB) and have to make some compromise.
d.) With a mapper different to MAPPER_NON UTF8 input is used. Instead of “\xe1” (on a display with Japanese font) or STR_ae simply use “ä”. When the string is read byte by byte , the “ä” will expand to “\0xc3\0xa4” or “Я” will expand to “0xd0\0xaf” or “ホ” will expand to “\0xe3\0x83\0x9b” To limit the used memory we can’t use all the possibilities UTF8 gives at the same time. We define a subset matching to the language or script we use.
The mapper functions will only catch the ‘lead in’ described in the mappers name. If the input they get does not match they’ll put out a ‘?’ or garbage. The last byte in the sequence ether points directly into a matching ISO10646 font or via a mapper_table into one of the HD44780 fonts. The mapper_tables do their best to find a similar symbol in the HD44780_fonts. For example replacing small letters with the matching capital letters. But they may fail to find something matching and will output a ‘?’. There are combinations of language and display what simply have no corresponding symbols - like Cyrillic on a Japanese display or visa versa - than the compiler will throw an error. In short: Chose a Mapper working with the symbols you want to use. Use only symbols matching the mapper. On FULL graphic displays all will be fine, but check for daring replacements or question-marks in the output of character based displays by defining SIMULATE_ROMFONT and trying the different variants. If you get a lot of question-marks on the Hitachi based displays with your new translation, maybe creating an additional language file with the format ‘language_xx_utf8.h’ is the way to go.
e.) Creating a new language file is not a big thing. Just make a new file with the format ‘language_xx.h’ or maybe ‘language.xx.utf8.h’, define a mapper and a font in there and translate some of the strings defined in language_en.h. You can drop the surrounding #ifndef #endif. You don’t have to translate all the stings - the missing one will be added by language_en.h - in English - of cause.
f.) If you cant find a matching mapper things will be a bit more complex. With the Hitachi based displays you will not have big chance to make something useful unless you have one with a matching charset. For a full graphic display - lets explain with - let’s say Greece. Find a matching charset. (http://en.wikipedia.org/wiki/Greek_and_Coptic) Provide a font containing the symbols in the right size. Normal ASCII in the lower 127 places, the upper with your selection. Write a mapper catching, in this case, 0xcd to 0xcf and add it to ‘utf_mapper.h’. In case of a ISO10646 font we have a MAPPER_ONE_TO_ONE and don’t have to make a table.
g.) If you discover enough useful symbols in one of the HD44780 fonts you can provide a mapping table. For example HD44780_WEST contains ‘alpha’, ‘beta’, ‘pi’, ‘Sigma’, ‘omega’ ‘My’ - what is not enough to make USEFUL table - I think.
h.) If you want to integrate an entirely new variant of a Hitachi based display. Add it in ‘Configuration.h’. Define mapper tables in ‘utf_mapper.h’. Maybe you need a new mapper function.
The length of the strings is limited. ‘17 chars’ was crude rule of thumb. Obviously 17 is to long for the 16x2 displays. A more exact rule would be max_strlen = Displaywidth - 2 - strlen(value to display behind). This is a bit complicated. So try and count is my rule of thumb.
On the 16x2 displays the strings are cut at the end to fit on the display. So it’s a good idea to make them differ early. (‘Somverylongoptionname x’ -> ‘x Somverylongoptionname’)
You’ll find all translatable strings in ‘language_en.h’. Please don’t translate any strings from ‘language.h’, this may break the serial protocol.
Define your hardware and the wanted language in ‘Configuration.h’. To find out what charset your hardware is, define language ‘test’ and compile. In the menu you will see two lines from the upper half of the charset.
If you get an error about missing mappers during compilation - lie about your displays hardware font to see at lest some garbage, or select an other language.
English works on all hardware.