mirror of
https://github.com/lvgl/lvgl.git
synced 2026-05-27 03:25:28 +08:00
feat(label): implement api to bind a translation tag to a label (#8948)
Co-authored-by: Liam Howatt <30486941+liamHowatt@users.noreply.github.com>
This commit is contained in:
@@ -76,6 +76,8 @@ These return a translated string which can be used with widgets:
|
|||||||
lv_dropdown_set_options(dd, lv_tr("color_list"));
|
lv_dropdown_set_options(dd, lv_tr("color_list"));
|
||||||
|
|
||||||
|
|
||||||
|
.. _translation_fallbacks:
|
||||||
|
|
||||||
Fallbacks
|
Fallbacks
|
||||||
---------
|
---------
|
||||||
|
|
||||||
@@ -89,6 +91,8 @@ Dynamically Updating UI Text
|
|||||||
|
|
||||||
When :cpp:expr:`lv_translation_set_language("language")` is called, LVGL sends ``LV_EVENT_TRANSLATION_LANGUAGE_CHANGED`` to every widget, allowing you to update text automatically.
|
When :cpp:expr:`lv_translation_set_language("language")` is called, LVGL sends ``LV_EVENT_TRANSLATION_LANGUAGE_CHANGED`` to every widget, allowing you to update text automatically.
|
||||||
|
|
||||||
|
The new language can be retrieved by either calling :cpp:expr:`lv_translation_get_language()` or by getting the event parameter in the event callback with :cpp:expr:`lv_event_get_param(e)`
|
||||||
|
|
||||||
Basic Example
|
Basic Example
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
@@ -99,6 +103,11 @@ Basic Example
|
|||||||
lv_obj_t * label = lv_event_get_target_obj(e);
|
lv_obj_t * label = lv_event_get_target_obj(e);
|
||||||
const char * tag = (const char *) lv_event_get_user_data(e);
|
const char * tag = (const char *) lv_event_get_user_data(e);
|
||||||
lv_label_set_text(label, lv_tr(tag));
|
lv_label_set_text(label, lv_tr(tag));
|
||||||
|
|
||||||
|
/* You can get the new language with `lv_event_get_param`*/
|
||||||
|
/* const char * language = (const char *) lv_event_get_param(e); */
|
||||||
|
/* or with `lv_translation_get_language` */
|
||||||
|
/* const char * language = lv_translation_get_language(); */
|
||||||
}
|
}
|
||||||
|
|
||||||
lv_obj_t * label = lv_label_create(lv_screen_active());
|
lv_obj_t * label = lv_label_create(lv_screen_active());
|
||||||
|
|||||||
@@ -76,6 +76,13 @@ they are stored in ROM memory, which is always accessible.
|
|||||||
realloc() will be forced every time the length of the string changes. That
|
realloc() will be forced every time the length of the string changes. That
|
||||||
MCU overhead can be avoided by doing the above.
|
MCU overhead can be avoided by doing the above.
|
||||||
|
|
||||||
|
Set translation tag
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
When using LVGL's translation module, you can bind a translation tag to a label directly with :cpp:expr:`lv_label_set_translation_tag(label, tag)`.
|
||||||
|
After this function is called, future changes to the language will automatically update the label's text to display the corresponding translation
|
||||||
|
for that tag in the new language.
|
||||||
|
|
||||||
.. _lv_label_newline:
|
.. _lv_label_newline:
|
||||||
|
|
||||||
Newline
|
Newline
|
||||||
|
|||||||
@@ -34,9 +34,7 @@ e.g., ``languages="en de hu"``. Language codes are free-form, but ISO-style code
|
|||||||
|
|
||||||
Each ``<translation>`` defines a ``tag``, which acts as the lookup key, and attributes for each language.
|
Each ``<translation>`` defines a ``tag``, which acts as the lookup key, and attributes for each language.
|
||||||
|
|
||||||
Translations may be omitted --- fallbacks will be applied when needed.
|
Translations may be omitted --- fallbacks will be applied when needed. See :ref:`translation_fallbacks` for more details.
|
||||||
|
|
||||||
TODO: link to more information about translation fallbacks: xml_translations_fallbacks
|
|
||||||
|
|
||||||
To register XML translations:
|
To register XML translations:
|
||||||
|
|
||||||
@@ -44,17 +42,3 @@ To register XML translations:
|
|||||||
- :cpp:expr:`lv_xml_translation_register_from_data(xml_string)`
|
- :cpp:expr:`lv_xml_translation_register_from_data(xml_string)`
|
||||||
|
|
||||||
Multiple XML sources can be registered; they will be merged and searched collectively.
|
Multiple XML sources can be registered; they will be merged and searched collectively.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Usage in XML
|
|
||||||
************
|
|
||||||
|
|
||||||
Some widget properties support a ``*-translated`` suffix to refer to translation tags. For example:
|
|
||||||
|
|
||||||
.. code-block:: xml
|
|
||||||
|
|
||||||
<lv_label text-translated="dog"/>
|
|
||||||
|
|
||||||
This sets the label's text to the translated string for ``"dog"``.
|
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
</styles>
|
</styles>
|
||||||
|
|
||||||
<view extends="lv_obj" style_radius="3" width="#size" height="content" styles="gray" style_bg_color="$bg_color" >
|
<view extends="lv_obj" style_radius="3" width="#size" height="content" styles="gray" style_bg_color="$bg_color" >
|
||||||
<lv_label text-translated="$title" align="left_mid"/>
|
<lv_label translation_tag="$title" align="left_mid"/>
|
||||||
<my_button btn_text="$action" align="right_mid">
|
<my_button btn_text="$action" align="right_mid">
|
||||||
<style name="$btn_rel_style"/>
|
<style name="$btn_rel_style"/>
|
||||||
<style name="$btn_pr_style" selector="pressed"/>
|
<style name="$btn_pr_style" selector="pressed"/>
|
||||||
|
|||||||
@@ -34,3 +34,10 @@ Monospace font
|
|||||||
|
|
||||||
.. lv_example:: widgets/label/lv_example_label_6
|
.. lv_example:: widgets/label/lv_example_label_6
|
||||||
:language: c
|
:language: c
|
||||||
|
|
||||||
|
Assign a translation tag to a label
|
||||||
|
-----------------------------------
|
||||||
|
|
||||||
|
.. lv_example:: widgets/label/lv_example_label_7
|
||||||
|
:language: c
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
#include "../../lv_examples.h"
|
||||||
|
|
||||||
|
#if LV_USE_TRANSLATION && LV_USE_DROPDOWN && LV_USE_LABEL && LV_BUILD_EXAMPLES
|
||||||
|
|
||||||
|
static const char * tags[] = {"tiger", "lion", "rabbit", "elephant", NULL};
|
||||||
|
static const char * languages[] = {"English", "Deutsch", "Español", NULL};
|
||||||
|
|
||||||
|
static void add_static_translations(void)
|
||||||
|
{
|
||||||
|
static const char * translations[] = {
|
||||||
|
"The Tiger", "Der Tiger", "El Tigre",
|
||||||
|
"The Lion", "Der Löwe", "El León",
|
||||||
|
"The Rabbit", "Das Kaninchen", "El Conejo",
|
||||||
|
"The Elephant", "Der Elefant", "El Elefante",
|
||||||
|
};
|
||||||
|
|
||||||
|
lv_translation_add_static(languages, tags, translations);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void language_change_cb(lv_event_t * e)
|
||||||
|
{
|
||||||
|
static char selected_lang[20];
|
||||||
|
|
||||||
|
lv_obj_t * dropdown = lv_event_get_target_obj(e);
|
||||||
|
lv_dropdown_get_selected_str(dropdown, selected_lang, sizeof(selected_lang));
|
||||||
|
lv_translation_set_language(selected_lang);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use a translation tag in labels
|
||||||
|
*/
|
||||||
|
void lv_example_label_7(void)
|
||||||
|
{
|
||||||
|
lv_obj_set_flex_flow(lv_screen_active(), LV_FLEX_FLOW_COLUMN);
|
||||||
|
lv_obj_set_flex_align(lv_screen_active(), LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
|
||||||
|
|
||||||
|
add_static_translations();
|
||||||
|
const size_t tag_count = sizeof(tags) / sizeof(tags[0]) - 1;
|
||||||
|
const size_t lang_count = sizeof(languages) / sizeof(languages[0]) - 1;
|
||||||
|
|
||||||
|
/* Create a dropdown to be able to select the language */
|
||||||
|
lv_obj_t * language_dropdown = lv_dropdown_create(lv_screen_active());
|
||||||
|
lv_dropdown_clear_options(language_dropdown);
|
||||||
|
|
||||||
|
for(size_t i = 0; i < lang_count; ++i) {
|
||||||
|
lv_dropdown_add_option(language_dropdown, languages[i], i);
|
||||||
|
}
|
||||||
|
|
||||||
|
lv_obj_add_event_cb(language_dropdown, language_change_cb, LV_EVENT_VALUE_CHANGED, NULL);
|
||||||
|
lv_translation_set_language("English");
|
||||||
|
|
||||||
|
/* Create a label for each tag */
|
||||||
|
for(size_t i = 0; i < tag_count; ++i) {
|
||||||
|
lv_obj_t * label = lv_label_create(lv_screen_active());
|
||||||
|
lv_label_set_translation_tag(label, tags[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /*LV_USE_TRANSLATION && LV_USE_DROPDOWN && LV_USE_LABEL && LV_BUILD_EXAMPLES*/
|
||||||
@@ -98,6 +98,7 @@ void lv_example_label_3(void);
|
|||||||
void lv_example_label_4(void);
|
void lv_example_label_4(void);
|
||||||
void lv_example_label_5(void);
|
void lv_example_label_5(void);
|
||||||
void lv_example_label_6(void);
|
void lv_example_label_6(void);
|
||||||
|
void lv_example_label_7(void);
|
||||||
|
|
||||||
void lv_example_led_1(void);
|
void lv_example_led_1(void);
|
||||||
|
|
||||||
|
|||||||
@@ -58,9 +58,8 @@ void lv_xml_label_apply(lv_xml_parser_state_t * state, const char ** attrs)
|
|||||||
if(lv_streq("text", name)) lv_label_set_text(item, value);
|
if(lv_streq("text", name)) lv_label_set_text(item, value);
|
||||||
else if(lv_streq("long_mode", name)) lv_label_set_long_mode(item, long_mode_text_to_enum_value(value));
|
else if(lv_streq("long_mode", name)) lv_label_set_long_mode(item, long_mode_text_to_enum_value(value));
|
||||||
#if LV_USE_TRANSLATION
|
#if LV_USE_TRANSLATION
|
||||||
if(lv_streq("text-translated", name)) lv_label_set_text(item, lv_tr(value));
|
else if(lv_streq("translation_tag", name)) lv_label_set_translation_tag(item, value);
|
||||||
#endif
|
#endif
|
||||||
if(lv_streq("long_mode", name)) lv_label_set_long_mode(item, long_mode_text_to_enum_value(value));
|
|
||||||
else if(lv_streq("bind_text", name)) {
|
else if(lv_streq("bind_text", name)) {
|
||||||
lv_subject_t * subject = lv_xml_get_subject(&state->scope, value);
|
lv_subject_t * subject = lv_xml_get_subject(&state->scope, value);
|
||||||
if(subject == NULL) {
|
if(subject == NULL) {
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
#include "../../stdlib/lv_sprintf.h"
|
#include "../../stdlib/lv_sprintf.h"
|
||||||
#include "../../stdlib/lv_string.h"
|
#include "../../stdlib/lv_string.h"
|
||||||
#include "../../others/observer/lv_observer_private.h"
|
#include "../../others/observer/lv_observer_private.h"
|
||||||
|
#include "../../others/translation/lv_translation.h"
|
||||||
|
|
||||||
/*********************
|
/*********************
|
||||||
* DEFINES
|
* DEFINES
|
||||||
@@ -48,6 +49,8 @@ static void lv_label_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
|
|||||||
static void lv_label_event(const lv_obj_class_t * class_p, lv_event_t * e);
|
static void lv_label_event(const lv_obj_class_t * class_p, lv_event_t * e);
|
||||||
static void draw_main(lv_event_t * e);
|
static void draw_main(lv_event_t * e);
|
||||||
|
|
||||||
|
static void set_text_internal(lv_obj_t * obj, const char * text);
|
||||||
|
static void remove_translation_tag(lv_obj_t * obj);
|
||||||
static void lv_label_refr_text(lv_obj_t * obj);
|
static void lv_label_refr_text(lv_obj_t * obj);
|
||||||
static void lv_label_revert_dots(lv_obj_t * label);
|
static void lv_label_revert_dots(lv_obj_t * label);
|
||||||
static void lv_label_set_dots(lv_obj_t * label, uint32_t dot_begin);
|
static void lv_label_set_dots(lv_obj_t * label, uint32_t dot_begin);
|
||||||
@@ -138,43 +141,8 @@ lv_obj_t * lv_label_create(lv_obj_t * parent)
|
|||||||
void lv_label_set_text(lv_obj_t * obj, const char * text)
|
void lv_label_set_text(lv_obj_t * obj, const char * text)
|
||||||
{
|
{
|
||||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||||
lv_label_t * label = (lv_label_t *)obj;
|
remove_translation_tag(obj);
|
||||||
|
set_text_internal(obj, text);
|
||||||
/*If text is NULL then just refresh with the current text*/
|
|
||||||
if(text == NULL) text = label->text;
|
|
||||||
|
|
||||||
lv_label_revert_dots(obj); /*In case text == label->text*/
|
|
||||||
const size_t text_len = get_text_length(text);
|
|
||||||
|
|
||||||
/*If set its own text then reallocate it (maybe its size changed)*/
|
|
||||||
if(label->text == text && label->static_txt == 0) {
|
|
||||||
label->text = lv_realloc(label->text, text_len);
|
|
||||||
LV_ASSERT_MALLOC(label->text);
|
|
||||||
if(label->text == NULL) return;
|
|
||||||
|
|
||||||
#if LV_USE_ARABIC_PERSIAN_CHARS
|
|
||||||
lv_text_ap_proc(label->text, label->text);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/*Free the old text*/
|
|
||||||
if(label->text != NULL && label->static_txt == 0) {
|
|
||||||
lv_free(label->text);
|
|
||||||
label->text = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
label->text = lv_malloc(text_len);
|
|
||||||
LV_ASSERT_MALLOC(label->text);
|
|
||||||
if(label->text == NULL) return;
|
|
||||||
|
|
||||||
copy_text_to_label(label, text);
|
|
||||||
|
|
||||||
/*Now the text is dynamically allocated*/
|
|
||||||
label->static_txt = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
lv_label_refr_text(obj);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void lv_label_set_text_fmt(lv_obj_t * obj, const char * fmt, ...)
|
void lv_label_set_text_fmt(lv_obj_t * obj, const char * fmt, ...)
|
||||||
@@ -190,6 +158,7 @@ void lv_label_set_text_vfmt(lv_obj_t * obj, const char * fmt, va_list args)
|
|||||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||||
LV_ASSERT_NULL(fmt);
|
LV_ASSERT_NULL(fmt);
|
||||||
|
|
||||||
|
remove_translation_tag(obj);
|
||||||
lv_obj_invalidate(obj);
|
lv_obj_invalidate(obj);
|
||||||
lv_label_t * label = (lv_label_t *)obj;
|
lv_label_t * label = (lv_label_t *)obj;
|
||||||
|
|
||||||
@@ -217,6 +186,7 @@ void lv_label_set_text_static(lv_obj_t * obj, const char * text)
|
|||||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||||
lv_label_t * label = (lv_label_t *)obj;
|
lv_label_t * label = (lv_label_t *)obj;
|
||||||
|
|
||||||
|
remove_translation_tag(obj);
|
||||||
if(label->static_txt == 0 && label->text != NULL) {
|
if(label->static_txt == 0 && label->text != NULL) {
|
||||||
lv_free(label->text);
|
lv_free(label->text);
|
||||||
label->text = NULL;
|
label->text = NULL;
|
||||||
@@ -230,6 +200,28 @@ void lv_label_set_text_static(lv_obj_t * obj, const char * text)
|
|||||||
lv_label_refr_text(obj);
|
lv_label_refr_text(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if LV_USE_TRANSLATION
|
||||||
|
void lv_label_set_translation_tag(lv_obj_t * obj, const char * tag)
|
||||||
|
{
|
||||||
|
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||||
|
lv_label_t * label = (lv_label_t *)obj;
|
||||||
|
if(!tag) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
char * new_tag = lv_strdup(tag);
|
||||||
|
LV_ASSERT_MALLOC(new_tag);
|
||||||
|
if(!new_tag) {
|
||||||
|
LV_LOG_WARN("Failed to allocate memory for new tag");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(label->translation_tag) {
|
||||||
|
lv_free(label->translation_tag);
|
||||||
|
}
|
||||||
|
label->translation_tag = new_tag;
|
||||||
|
set_text_internal(obj, lv_tr(tag));
|
||||||
|
}
|
||||||
|
#endif /*LV_USE_TRANSLATION*/
|
||||||
|
|
||||||
void lv_label_set_long_mode(lv_obj_t * obj, lv_label_long_mode_t long_mode)
|
void lv_label_set_long_mode(lv_obj_t * obj, lv_label_long_mode_t long_mode)
|
||||||
{
|
{
|
||||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||||
@@ -796,6 +788,10 @@ static void lv_label_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
|
|||||||
|
|
||||||
if(!label->static_txt) lv_free(label->text);
|
if(!label->static_txt) lv_free(label->text);
|
||||||
label->text = NULL;
|
label->text = NULL;
|
||||||
|
#if LV_USE_TRANSLATION
|
||||||
|
if(label->translation_tag) lv_free(label->translation_tag);
|
||||||
|
label->translation_tag = NULL;
|
||||||
|
#endif /*LV_USE_TRANSLATION*/
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lv_label_event(const lv_obj_class_t * class_p, lv_event_t * e)
|
static void lv_label_event(const lv_obj_class_t * class_p, lv_event_t * e)
|
||||||
@@ -861,7 +857,17 @@ static void lv_label_event(const lv_obj_class_t * class_p, lv_event_t * e)
|
|||||||
}
|
}
|
||||||
else if(code == LV_EVENT_DRAW_MAIN) {
|
else if(code == LV_EVENT_DRAW_MAIN) {
|
||||||
draw_main(e);
|
draw_main(e);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
#if LV_USE_TRANSLATION
|
||||||
|
else if(code == LV_EVENT_TRANSLATION_LANGUAGE_CHANGED) {
|
||||||
|
lv_label_t * label = (lv_label_t *)obj;
|
||||||
|
if(label->translation_tag) {
|
||||||
|
const char * new_text = lv_tr(label->translation_tag);
|
||||||
|
set_text_internal(obj, new_text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void draw_main(lv_event_t * e)
|
static void draw_main(lv_event_t * e)
|
||||||
@@ -978,6 +984,59 @@ static void draw_main(lv_event_t * e)
|
|||||||
layer->_clip_area = clip_area_ori;
|
layer->_clip_area = clip_area_ori;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void set_text_internal(lv_obj_t * obj, const char * text)
|
||||||
|
{
|
||||||
|
lv_label_t * label = (lv_label_t *)obj;
|
||||||
|
|
||||||
|
/*If text is NULL then just refresh with the current text*/
|
||||||
|
if(text == NULL) text = label->text;
|
||||||
|
|
||||||
|
lv_label_revert_dots(obj); /*In case text == label->text*/
|
||||||
|
const size_t text_len = get_text_length(text);
|
||||||
|
|
||||||
|
/*If set its own text then reallocate it (maybe its size changed)*/
|
||||||
|
if(label->text == text && label->static_txt == 0) {
|
||||||
|
label->text = lv_realloc(label->text, text_len);
|
||||||
|
LV_ASSERT_MALLOC(label->text);
|
||||||
|
if(label->text == NULL) return;
|
||||||
|
|
||||||
|
#if LV_USE_ARABIC_PERSIAN_CHARS
|
||||||
|
lv_text_ap_proc(label->text, label->text);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/*Free the old text*/
|
||||||
|
if(label->text != NULL && label->static_txt == 0) {
|
||||||
|
lv_free(label->text);
|
||||||
|
label->text = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
label->text = lv_malloc(text_len);
|
||||||
|
LV_ASSERT_MALLOC(label->text);
|
||||||
|
if(label->text == NULL) return;
|
||||||
|
|
||||||
|
copy_text_to_label(label, text);
|
||||||
|
|
||||||
|
/*Now the text is dynamically allocated*/
|
||||||
|
label->static_txt = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
lv_label_refr_text(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void remove_translation_tag(lv_obj_t * obj)
|
||||||
|
{
|
||||||
|
LV_UNUSED(obj);
|
||||||
|
#if LV_USE_TRANSLATION
|
||||||
|
lv_label_t * label = (lv_label_t *)obj;
|
||||||
|
/* Remove translation tag so we don't update the text automatically if the language changes*/
|
||||||
|
if(label->translation_tag) {
|
||||||
|
lv_free(label->translation_tag);
|
||||||
|
label->translation_tag = NULL;
|
||||||
|
}
|
||||||
|
#endif /*LV_USE_TRANSLATION*/
|
||||||
|
}
|
||||||
static void overwrite_anim_property(lv_anim_t * dest, const lv_anim_t * src, lv_label_long_mode_t mode)
|
static void overwrite_anim_property(lv_anim_t * dest, const lv_anim_t * src, lv_label_long_mode_t mode)
|
||||||
{
|
{
|
||||||
switch(mode) {
|
switch(mode) {
|
||||||
@@ -1409,7 +1468,5 @@ static void label_text_observer_cb(lv_observer_t * observer, lv_subject_t * subj
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /*LV_USE_LABEL*/
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
#endif /*LV_USE_LABEL*/
|
||||||
|
|||||||
@@ -158,6 +158,19 @@ void lv_label_set_text_selection_end(lv_obj_t * obj, uint32_t index);
|
|||||||
*/
|
*/
|
||||||
void lv_label_set_recolor(lv_obj_t * obj, bool en);
|
void lv_label_set_recolor(lv_obj_t * obj, bool en);
|
||||||
|
|
||||||
|
#if LV_USE_TRANSLATION
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assign a translation tag for this label. Memory will be allocated to store the tag by the label.
|
||||||
|
* The label text will automatically update when the language is changed via `lv_translation_set_language`.
|
||||||
|
* @param obj pointer to a label object
|
||||||
|
* @param tag '\0' terminated character string.
|
||||||
|
*/
|
||||||
|
void lv_label_set_translation_tag(lv_obj_t * obj, const char * tag);
|
||||||
|
|
||||||
|
#endif /*LV_USE_TRANSLATION*/
|
||||||
|
|
||||||
|
|
||||||
/*=====================
|
/*=====================
|
||||||
* Getter functions
|
* Getter functions
|
||||||
*====================*/
|
*====================*/
|
||||||
|
|||||||
@@ -31,6 +31,9 @@ extern "C" {
|
|||||||
struct _lv_label_t {
|
struct _lv_label_t {
|
||||||
lv_obj_t obj;
|
lv_obj_t obj;
|
||||||
char * text;
|
char * text;
|
||||||
|
#if LV_USE_TRANSLATION
|
||||||
|
char * translation_tag;
|
||||||
|
#endif /*LV_USE_TRANSLATION*/
|
||||||
char dot[LV_LABEL_DOT_NUM + 1]; /**< Bytes that have been replaced with dots */
|
char dot[LV_LABEL_DOT_NUM + 1]; /**< Bytes that have been replaced with dots */
|
||||||
uint32_t dot_begin; /**< Offset where bytes have been replaced with dots */
|
uint32_t dot_begin; /**< Offset where bytes have been replaced with dots */
|
||||||
|
|
||||||
|
|||||||
@@ -789,5 +789,65 @@ void test_label_wrap_mode_clip(void)
|
|||||||
lv_snprintf(buf, sizeof(buf), "widgets/label_wrap_clip.png");
|
lv_snprintf(buf, sizeof(buf), "widgets/label_wrap_clip.png");
|
||||||
TEST_ASSERT_EQUAL_SCREENSHOT(buf);
|
TEST_ASSERT_EQUAL_SCREENSHOT(buf);
|
||||||
}
|
}
|
||||||
|
void test_label_translation_tag(void)
|
||||||
|
{
|
||||||
|
static const char * tags[] = {"tiger", NULL};
|
||||||
|
static const char * languages[] = {"en", "de", "es", NULL};
|
||||||
|
static const char * translations[] = { "The Tiger", "Der Tiger", "El Tigre" };
|
||||||
|
lv_translation_add_static(languages, tags, translations);
|
||||||
|
label = lv_label_create(NULL);
|
||||||
|
lv_label_set_translation_tag(label, "tiger");
|
||||||
|
|
||||||
|
lv_translation_set_language("en");
|
||||||
|
TEST_ASSERT_EQUAL_STRING(lv_label_get_text(label), "The Tiger");
|
||||||
|
|
||||||
|
lv_translation_set_language("de");
|
||||||
|
TEST_ASSERT_EQUAL_STRING(lv_label_get_text(label), "Der Tiger");
|
||||||
|
|
||||||
|
lv_translation_set_language("es");
|
||||||
|
TEST_ASSERT_EQUAL_STRING(lv_label_get_text(label), "El Tigre");
|
||||||
|
|
||||||
|
/* Unknown language translates to the tag */
|
||||||
|
lv_translation_set_language("fr");
|
||||||
|
TEST_ASSERT_EQUAL_STRING(lv_label_get_text(label), "tiger");
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_label_setting_text_disables_translation(void)
|
||||||
|
{
|
||||||
|
static const char * tags[] = {"tiger", NULL};
|
||||||
|
static const char * languages[] = {"en", "de", "es", NULL};
|
||||||
|
static const char * translations[] = { "The Tiger", "Der Tiger", "El Tigre" };
|
||||||
|
lv_translation_add_static(languages, tags, translations);
|
||||||
|
label = lv_label_create(NULL);
|
||||||
|
lv_label_set_translation_tag(label, "tiger");
|
||||||
|
|
||||||
|
lv_translation_set_language("en");
|
||||||
|
TEST_ASSERT_EQUAL_STRING(lv_label_get_text(label), "The Tiger");
|
||||||
|
|
||||||
|
lv_translation_set_language("de");
|
||||||
|
TEST_ASSERT_EQUAL_STRING(lv_label_get_text(label), "Der Tiger");
|
||||||
|
|
||||||
|
/* Using set text should unbind the translation tag*/
|
||||||
|
lv_label_set_text(label, "Hello world");
|
||||||
|
lv_translation_set_language("de");
|
||||||
|
TEST_ASSERT_EQUAL_STRING(lv_label_get_text(label), "Hello world");
|
||||||
|
|
||||||
|
lv_label_set_translation_tag(label, "tiger");
|
||||||
|
TEST_ASSERT_EQUAL_STRING(lv_label_get_text(label), "Der Tiger");
|
||||||
|
|
||||||
|
/* Using set text static should unbind the translation tag*/
|
||||||
|
lv_label_set_text_static(label, "Hello world");
|
||||||
|
lv_translation_set_language("en");
|
||||||
|
TEST_ASSERT_EQUAL_STRING(lv_label_get_text(label), "Hello world");
|
||||||
|
lv_label_set_translation_tag(label, "tiger");
|
||||||
|
TEST_ASSERT_EQUAL_STRING(lv_label_get_text(label), "The Tiger");
|
||||||
|
|
||||||
|
/* Using set text fmt should unbind the translation tag*/
|
||||||
|
lv_label_set_text_fmt(label, "Hello world %d", 1);
|
||||||
|
lv_translation_set_language("de");
|
||||||
|
TEST_ASSERT_EQUAL_STRING(lv_label_get_text(label), "Hello world 1");
|
||||||
|
lv_label_set_translation_tag(label, "tiger");
|
||||||
|
TEST_ASSERT_EQUAL_STRING(lv_label_get_text(label), "Der Tiger");
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -62,5 +62,21 @@ void test_xml_label_with_attrs(void)
|
|||||||
|
|
||||||
TEST_ASSERT_EQUAL_SCREENSHOT("xml/lv_label.png");
|
TEST_ASSERT_EQUAL_SCREENSHOT("xml/lv_label.png");
|
||||||
}
|
}
|
||||||
|
void test_xml_label_translation_tag(void)
|
||||||
|
{
|
||||||
|
static const char * tags[] = {"tiger", NULL};
|
||||||
|
static const char * languages[] = {"en", "de", "es", NULL};
|
||||||
|
static const char * translations[] = { "The Tiger", "Der Tiger", "El Tigre" };
|
||||||
|
lv_translation_add_static(languages, tags, translations);
|
||||||
|
|
||||||
|
lv_obj_t * scr = lv_screen_active();
|
||||||
|
const char * label1_attrs[] = {
|
||||||
|
"translation_tag", "tiger",
|
||||||
|
NULL, NULL,
|
||||||
|
};
|
||||||
|
lv_obj_t * label = lv_xml_create(scr, "lv_label", label1_attrs);
|
||||||
|
lv_translation_set_language("de");
|
||||||
|
TEST_ASSERT_EQUAL_STRING(lv_label_get_text(label), "Der Tiger");
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+1
-1
@@ -14,7 +14,7 @@ Example
|
|||||||
</enumdef>
|
</enumdef>
|
||||||
|
|
||||||
<prop name="text" type="string" />
|
<prop name="text" type="string" />
|
||||||
<prop name="text-translated" type="string" />
|
<prop name="translation_tag" type="string" />
|
||||||
<prop name="long_mode" type="enum:lv_label_long_mode" />
|
<prop name="long_mode" type="enum:lv_label_long_mode" />
|
||||||
<prop name="bind_text">
|
<prop name="bind_text">
|
||||||
<param name="bind_text" type="subject" />
|
<param name="bind_text" type="subject" />
|
||||||
|
|||||||
Reference in New Issue
Block a user