Multi-lingual applications

I’m a new member of the LVGL family and trying to find my way in this new territory.
In this matter, the existing examples are indeed very helpful.

But there is one question I am currently struggling with: what strategy do I need to choose to make my application multilingual?
For example the list widget: the selection can only be distinguished by the text itself.

lv_list_add_button(list1, LV_SYMBOL_FILE, "New");

… and the function

lv_list_get_button_text(...);

returns “New”
As a result, I have to write a separate lv_list_get_button_text() for each language.
Not exactly what a programmer would want.
It would be desirable if I could add to the function
lv_list_add_button() an additional numeric ID.
Then I could, for example, use lv_list_get_button_ID() to clearly recognize the selection.

So, I assume that others have also faced this problem and that a solution already exists. I am curious! :slight_smile:

In lv_obj.h I have added the variable

uint16_t extra_id

to the structure of lv_obj_t. I also changed the function lv_list_add_button

lv_list_add_button(..., uint16_t id)
...
...
obj->extra_id = id;

Regardless of the language I can now determine the selection using extra_id.
Okay, I have to make sure that I always make this change in future updates.
But what the heck: better than any if-else orgy with strcmp() in every branch.

Hello,

What do you mean by “selection”? If you want to know which button has been pressed, the lv_list_add_button function returns an lv_obj_t* of type button.
You can then assign a callback to this button to respond to it being pressed.

If you have many buttons you can add an a callback to the list that gets called on CLICKED event, here you can also find out which button has been pressed by the lv_event_t* parameter.

As I have already mentioned, I have only just begun to familiarize myself with LVGL. So it’s quite possible that I’m missing something.
As far as I understand it, you can only use lv_list_get_button_text() to determine what has been selected. And only as text.
If this assumption is correct, then I have quite a problem finding out what has just been selected in a multilingual application. Even if it is only monolingual, I would prefer to compare numerical values and not work with strcmp().

I’m not sure how to explain this to someone who is new, but take a look at the example code here: List (lv_list) — LVGL documentation

It shows you how to add callbacks to buttons and lists. You can identify which button is pressed based on the lv_obj_t* in the lv_event_t* parameter of these callbacks.

Hi Tinus
I know this example. And in this example I have seen that only the text value can be determined. Let me illustrate this with an example.
The first button is
english: New
french: Nouveau
german: Neu
and so on.
The second button
english: Old
french: Ancien
german: Alt
and so on.

So with the function lv_list_get_button_text() I got a pointer to this value. And than I have to test:

if (strcmp(msg, "New") == 0) || (strcmp(msg, "Nouveau") == 0) || strcmp(msg, "Neu") == 0) {
 // bla bla bla
}

What I would prefer is a function that returns the selection as a number. Because then I would only have to compare one number.

if (selection == 1) { // button new was selected
  // bla bla bla
}

I hope that I have succeeded in explaining where I see a problem. And, of course, I hope that this is not a problem at all and can be solved with in-house tools.

1 Like

Hello,

I see what you mean now.
The best option (without modifying the source code of LVGL itself) would be to add user data to these buttons upon creation.

For instance (typing from memory here… excuse any errors!):

#DEFINE SOME_ID 1

// Create button and add user data
lv_obj_t * btn = lv_list_add_button(&list, ..., "New");
uint16_t* id = (uint16_t*)lv_malloc(sizeof(uint16_t));
*id = SOME_ID;
lv_obj_set_user_data(btn, id);

// Inside your list CLICK EVENT callback: 
lv_obj_t* btn = lv_event_get_target(e);

uint16_t id = (uint16_t*)lv_obj_get_get_user_data(btn);

// Do something with this ID...



This approach does indeed seem to be a solution with in-house resources.
But personally I would be reluctant to use malloc() so generously: the risk of forgetting to free the memory again is too great for me.
So I will continue with my patch. Nevertheless, many thanks for your efforts. At least I have clarity in my head about this.

You can just assign the integer ID to user data without having to allocate anything. I.e.,

lv_obj_set_user_data(btn, (void *)SOME_ID);
1 Like

It works! :champagne:
Instead of the functions I prefer to access the struct elements directly and hope that at some point the name will not be changed :pray:

But you have to be careful when going back and forth with pointers.

uint16_t val = (uint16_t)btn->user_data;  // will not compile
uint16_t val = (uint32_t)btn->user_data;  // okay (STM32 uses 32bit pointers)
uint16_t val = (uint16_t)(size_t)btn->user_data;  // best solution

gneverov, thank you very very much!!