| Deutsch English Français Italiano |
|
<votcl3$nc20$1@dont-email.me> View for Bookmarking (what is this?) Look up another Usenet article |
Path: ...!eternal-september.org!feeder3.eternal-september.org!news.eternal-september.org!eternal-september.org!.POSTED!not-for-mail
From: pozz <pozzugno@gmail.com>
Newsgroups: comp.arch.embedded
Subject: Re: How to add the second (or other) languages
Date: Sun, 16 Feb 2025 19:59:58 +0100
Organization: A noiseless patient Spider
Lines: 160
Message-ID: <votcl3$nc20$1@dont-email.me>
References: <voii3i$28jmm$1@dont-email.me>
<voioe3.598.1@stefan.msgid.phost.de> <voiu1q$2f5ap$1@dont-email.me>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 8bit
Injection-Date: Sun, 16 Feb 2025 20:00:52 +0100 (CET)
Injection-Info: dont-email.me; posting-host="f74bdbe09773e4d813c1959798f2cd87";
logging-data="766016"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1+gitiom2dYl2gaW1+gVzzR4bKJSwhLqCA="
User-Agent: Mozilla Thunderbird
Cancel-Lock: sha1:zi0aCKQMvL6fC+LMXMtYVZSAiKs=
In-Reply-To: <voiu1q$2f5ap$1@dont-email.me>
Content-Language: it
Bytes: 7205
Il 12/02/2025 20:50, David Brown ha scritto:
> On 12/02/2025 18:14, Stefan Reuther wrote:
>> Am 12.02.2025 um 17:26 schrieb pozz:
>>> #if LANGUAGE_ITALIAN
>>> # define STRING123 "Evento %d: accensione"
>>> #elif LANGUAGE_ENGLISH
>>> # define STRING123 "Event %d: power up"
>>> #endif
>> [...]
>>> Another approach is giving the user the possibility to change the
>>> language at runtime, maybe with an option on the display. In some cases,
>>> I have enough memory to store all the strings in all languages.
>>
>> Put the strings into a structure.
>>
>> struct Strings {
>> const char* power_up_message;
>> };
>>
>> I hate global variables, so I pass a pointer to the structure to every
>> function that needs it (but of course you can also make a global
>> variable).
>>
>> Then, on language change, just point your structure pointer elsewhere,
>> or load the strings from secondary storage.
>>
>> One disadvantage is that this loses you the compiler warnings for
>> mismatching printf specifiers.
>>
>>> I know there are many possible solutions, but I'd like to know some
>>> suggestions from you. For example, it could be nice if there was some
>>> tool that automatically extracts all the strings used in the source code
>>> and helps managing more languages.
>>
>> There's packages like gettext. You tag your strings as
>> 'printf(_("Event %d"), e)', and the 'xgettext' command will extract them
>> all into a .po file. Other tools help you manage these files (e.g.
>> 'msgmerge'; Emacs 'po-mode'), and gcc knows how to do proper printf
>> warnings.
>>
>> The .po file is a mapping from English to Whateverish strings. So you
>> would convert that into some space-efficient resource file, and
>> implement the '_' macro/function to perform the mapping. The
>> disadvantage is that this takes lot of memory because your app needs to
>> have both the English and the translated strings in memory. But unless
>> you also use a fancy preprocessor that translates your code to
>> 'printf(getstring(STR123), e)', I don't see how to avoid that. In C++20,
>> you might come up with some compile-time hashing...
>>
>> I wouldn't use that on a microcontroller, but it's nice for desktop apps.
>>
>>
>> Stefan
>
>
> You don't need a very fancy pre-processor to handle this yourself, if
> you are happy to make a few changes to the code. Have your code use
> something like :
>
> #define DisplayPrintf(id, desc, args...) \
> display_printf(strings[language][string_ ## id], ## x)
>
> Use it like :
>
> DisplayPrintf(event_type_on, "Event on", ev->idx);
>
>
> A little Python preprocessor script can chew through all your C files
> and identify each call to "DisplayPrintf".
Little... yes, it would be little, but not simple, at least for me. How
to write a correct C preprocessor in Python?
This preprocessor should ingest a C source file after it is preprocessed
by the standard C preprocessor for the specific build you are doing.
For example, you could have a C source file that contains:
#if BUILD == BUILD_FULL
DisplayPrintf(msg, "Press (1) for simple process, (2) for advanced
process");
x = wait_keypress();
if (x == '1') do_simple();
if (x == '2') do_adv();
#elif BUILD == BUILD_LIGHT
do_simple();
#endif
If I'm building the project as BUILD_FULL, there's at least one
additional string to translate.
Another big problem is the Python preprocessor should understand C
syntax; it shouldn't simply search for DisplayPrintf occurrences.
For example:
/* DisplayPrintf(old_string, "This is an old message"); */
DisplayPrintf(new_string, "This is a new message");
Of course, only one string is present in the source file, but it's not
simple to extract it.
> It can collect together all
> the id's and generate a header with something like :
>
> typedef enum {
> string_event_type_on, ...
> } string_index;
> enum { no_of_strings = ... };
>
> enum {
> lang_English, lang_Italian, ...
> } language_index;
> enum { no_of_languages = ... };
>
> extern language_index language; // global var :-)
> extern const char* strings[no_of_languages][no_of_strings];
>
> Then it will have a C file :
>
> #include "language.h"
>
> language_index language;
> const char* strings[no_of_languages][no_of_strings] = {
> { // English
> "Event %d: power up", // Event on
> ...
> }
> { // Italian
> "Evento %d: accensione", // Event on
> }
> }
>
> It would generate the strings based on language files:
>
> # english.txt
> event_type_on : Event %d: power up
> ...
>
> If the preprocessor finds a use of DisplayPrintf where the id (which can
> be as long or short as you want, but can't have spaces or awkward
> characters) does not match the description, it should give an error -
> duplicate uses of the same pair are skipped. (You could just use an id
> and no description if you prefer.)
>
> Any ids that are not in the language files will be printed out or put in
> a file, ids that are in the language files but not used in the program
> will give warnings, etc.
>
> It can all be done in a manner that makes it easy to get right, hard to
> get wrong, and will not cause trouble as strings are added or removed.
>
> It would be a lot simpler than gettext, and use minimal runtime space
> and time. And it should be straightforward to change if you want to
> have string tables stored externally or something like that. (I've made
> systems with string tables in an external serial eprom, for example.)
Thanks for the suggestion, the idea is great. However I'm not able to
write a Python preprocessor that works well.