[evolution-data-server] Calendar: Add functions to handle LANGUAGE parameter on properties



commit 5170198bb85fb0b8f6bcc351e78f1219b5719413
Author: Milan Crha <mcrha redhat com>
Date:   Wed Jun 8 18:54:02 2022 +0200

    Calendar: Add functions to handle LANGUAGE parameter on properties
    
    This helps to read properties related only to certain language/locale.
    
    Related to https://gitlab.gnome.org/GNOME/evolution/-/issues/876

 .../evolution-data-server-docs.sgml.in             |   4 +
 src/calendar/libecal/e-cal-component-alarm.c       |  44 +--
 src/calendar/libecal/e-cal-component-text.c        | 181 +++++++++++-
 src/calendar/libecal/e-cal-component-text.h        |  15 +
 src/calendar/libecal/e-cal-component.c             | 205 ++++++++++---
 src/calendar/libecal/e-cal-component.h             |  15 +
 src/calendar/libecal/e-cal-util.c                  | 126 ++++++++
 src/calendar/libecal/e-cal-util.h                  |   4 +
 tests/libecal/test-cal-component.c                 | 328 ++++++++++++++++++++-
 9 files changed, 834 insertions(+), 88 deletions(-)
---
diff --git a/docs/reference/evolution-data-server/evolution-data-server-docs.sgml.in 
b/docs/reference/evolution-data-server/evolution-data-server-docs.sgml.in
index 30a95ea97..3cdabb3dd 100644
--- a/docs/reference/evolution-data-server/evolution-data-server-docs.sgml.in
+++ b/docs/reference/evolution-data-server/evolution-data-server-docs.sgml.in
@@ -362,6 +362,10 @@
     <title>Index of deprecated symbols</title>
     <xi:include href="xml/api-index-deprecated.xml"><xi:fallback /></xi:include>
   </index>
+  <index id="api-index-3-46" role="3.46">
+    <title>Index of new symbols in 3.46</title>
+    <xi:include href="xml/api-index-3.46.xml"><xi:fallback /></xi:include>
+  </index>
   <index id="api-index-3-44" role="3.44">
     <title>Index of new symbols in 3.44</title>
     <xi:include href="xml/api-index-3.44.xml"><xi:fallback /></xi:include>
diff --git a/src/calendar/libecal/e-cal-component-alarm.c b/src/calendar/libecal/e-cal-component-alarm.c
index 6a1d0c073..1f146978c 100644
--- a/src/calendar/libecal/e-cal-component-alarm.c
+++ b/src/calendar/libecal/e-cal-component-alarm.c
@@ -309,27 +309,13 @@ e_cal_component_alarm_set_from_component (ECalComponentAlarm *alarm,
                        break;
 
                case I_CAL_SUMMARY_PROPERTY:
-                       if (i_cal_property_get_summary (prop)) {
-                               ICalParameter *param;
-
-                               param = i_cal_property_get_first_parameter (prop, I_CAL_ALTREP_PARAMETER);
-                               e_cal_component_alarm_take_summary (alarm,
-                                       e_cal_component_text_new (i_cal_property_get_summary (prop),
-                                       param ? i_cal_parameter_get_altrep (param) : NULL));
-                               g_clear_object (&param);
-                       }
+                       if (i_cal_property_get_summary (prop))
+                               e_cal_component_alarm_take_summary (alarm, 
e_cal_component_text_new_from_property (prop));
                        break;
 
                case I_CAL_DESCRIPTION_PROPERTY:
-                       if (i_cal_property_get_description (prop)) {
-                               ICalParameter *param;
-
-                               param = i_cal_property_get_first_parameter (prop, I_CAL_ALTREP_PARAMETER);
-                               e_cal_component_alarm_take_description (alarm,
-                                       e_cal_component_text_new (i_cal_property_get_description (prop),
-                                       param ? i_cal_parameter_get_altrep (param) : NULL));
-                               g_clear_object (&param);
-                       }
+                       if (i_cal_property_get_description (prop))
+                               e_cal_component_alarm_take_description (alarm, 
e_cal_component_text_new_from_property (prop));
                        break;
 
                case I_CAL_DURATION_PROPERTY:
@@ -524,16 +510,7 @@ e_cal_component_alarm_fill_component (ECalComponentAlarm *alarm,
                prop = i_cal_property_new_summary (e_cal_component_text_get_value (alarm->summary));
 
                if (prop) {
-                       const gchar *altrep = e_cal_component_text_get_altrep (alarm->summary);
-
-                       if (altrep && *altrep) {
-                               ICalParameter *param;
-
-                               param = i_cal_parameter_new_altrep (altrep);
-                               if (param)
-                                       i_cal_property_take_parameter (prop, param);
-                       }
-
+                       e_cal_component_text_fill_property (alarm->summary, prop);
                        i_cal_component_take_property (component, prop);
                }
        }
@@ -542,16 +519,7 @@ e_cal_component_alarm_fill_component (ECalComponentAlarm *alarm,
                prop = i_cal_property_new_description (e_cal_component_text_get_value (alarm->description));
 
                if (prop) {
-                       const gchar *altrep = e_cal_component_text_get_altrep (alarm->description);
-
-                       if (altrep && *altrep) {
-                               ICalParameter *param;
-
-                               param = i_cal_parameter_new_altrep (altrep);
-                               if (param)
-                                       i_cal_property_take_parameter (prop, param);
-                       }
-
+                       e_cal_component_text_fill_property (alarm->description, prop);
                        i_cal_component_take_property (component, prop);
                }
        }
diff --git a/src/calendar/libecal/e-cal-component-text.c b/src/calendar/libecal/e-cal-component-text.c
index 332468604..c5006815c 100644
--- a/src/calendar/libecal/e-cal-component-text.c
+++ b/src/calendar/libecal/e-cal-component-text.c
@@ -33,6 +33,7 @@ G_DEFINE_BOXED_TYPE (ECalComponentText, e_cal_component_text, e_cal_component_te
 struct _ECalComponentText {
        gchar *value;
        gchar *altrep;
+       gchar *language;
 };
 
 /**
@@ -61,6 +62,31 @@ e_cal_component_text_new (const gchar *value,
        return text;
 }
 
+/**
+ * e_cal_component_text_new_from_property:
+ * @property: an #ICalProperty
+ *
+ * Created a new #ECalComponentText filled with values from the @property.
+ * The @property should hold a text value.
+ *
+ * Returns: (transfer full): a newly allocated #ECalComponentText
+ *
+ * Since: 3.46
+ **/
+ECalComponentText *
+e_cal_component_text_new_from_property (const ICalProperty *property)
+{
+       ECalComponentText *text;
+
+       g_return_val_if_fail (I_CAL_IS_PROPERTY (property), NULL);
+
+       text = e_cal_component_text_new (NULL, NULL);
+
+       e_cal_component_text_set_from_property (text, property);
+
+       return text;
+}
+
 /**
  * e_cal_component_text_copy:
  * @text: (not nullable): an #ECalComponentText to copy
@@ -74,9 +100,14 @@ e_cal_component_text_new (const gchar *value,
 ECalComponentText *
 e_cal_component_text_copy (const ECalComponentText *text)
 {
+       ECalComponentText *copy;
+
        g_return_val_if_fail (text != NULL, NULL);
 
-       return e_cal_component_text_new (text->value, text->altrep);
+       copy = e_cal_component_text_new (text->value, text->altrep);
+       e_cal_component_text_set_language (copy, text->language);
+
+       return copy;
 }
 
 /**
@@ -96,10 +127,117 @@ e_cal_component_text_free (gpointer text)
        if (te) {
                g_free (te->value);
                g_free (te->altrep);
+               g_free (te->language);
                g_slice_free (ECalComponentText, te);
        }
 }
 
+/**
+ * e_cal_component_text_set_from_property:
+ * @text: an #ECalComponentText
+ * @property: an #ICalProperty
+ *
+ * Fill the @text structure with the information from the @property.
+ * The @property should hold a text value.
+ *
+ * Since: 3.46
+ **/
+void
+e_cal_component_text_set_from_property (ECalComponentText *text,
+                                       const ICalProperty *property)
+{
+       ICalValue *value;
+       ICalParameter *param;
+
+       g_return_if_fail (text != NULL);
+       g_return_if_fail (I_CAL_IS_PROPERTY (property));
+
+       value = i_cal_property_get_value (property);
+
+       if (value && i_cal_value_isa (value) == I_CAL_TEXT_VALUE) {
+               e_cal_component_text_set_value (text, i_cal_value_get_text (value));
+       } else {
+               e_cal_component_text_set_value (text, NULL);
+       }
+       g_clear_object (&value);
+
+       param = i_cal_property_get_first_parameter ((ICalProperty *) property, I_CAL_ALTREP_PARAMETER);
+       e_cal_component_text_set_altrep (text, param ? i_cal_parameter_get_altrep (param) : NULL);
+       g_clear_object (&param);
+
+       param = i_cal_property_get_first_parameter ((ICalProperty *) property, I_CAL_LANGUAGE_PARAMETER);
+       e_cal_component_text_set_language (text, param ? i_cal_parameter_get_language (param) : NULL);
+       g_clear_object (&param);
+}
+
+/**
+ * e_cal_component_text_fill_property:
+ * @text: an #ECalComponentText
+ * @property: an #ICalProperty
+ *
+ * Fills the @property with the content of the @text.
+ *
+ * Since: 3.46
+ **/
+void
+e_cal_component_text_fill_property (const ECalComponentText *text,
+                                   ICalProperty *property)
+{
+       ICalValue *value;
+       ICalParameter *param;
+       const gchar *str;
+
+       g_return_if_fail (text != NULL);
+       g_return_if_fail (I_CAL_IS_PROPERTY (property));
+
+       str = e_cal_component_text_get_value (text) ? e_cal_component_text_get_value (text) : "";
+       value = i_cal_property_get_value (property);
+
+       if (value && i_cal_value_isa (value) == I_CAL_TEXT_VALUE) {
+               i_cal_value_set_text (value, str);
+               e_cal_component_text_get_value (text);
+       } else {
+               value = i_cal_value_new_text (str);
+               i_cal_property_set_value (property, value);
+       }
+
+       g_clear_object (&value);
+
+       str = e_cal_component_text_get_altrep (text);
+       param = i_cal_property_get_first_parameter (property, I_CAL_ALTREP_PARAMETER);
+
+       if (str && *str) {
+               if (param) {
+                       i_cal_parameter_set_altrep (param, str);
+               } else {
+                       param = i_cal_parameter_new_altrep (str);
+                       i_cal_property_take_parameter (property, param);
+                       param = NULL;
+               }
+       } else if (param) {
+               i_cal_property_remove_parameter_by_kind (property, I_CAL_ALTREP_PARAMETER);
+       }
+
+       g_clear_object (&param);
+
+       str = e_cal_component_text_get_language (text);
+       param = i_cal_property_get_first_parameter (property, I_CAL_LANGUAGE_PARAMETER);
+
+       if (str && *str) {
+               if (param) {
+                       i_cal_parameter_set_language (param, str);
+               } else {
+                       param = i_cal_parameter_new_language (str);
+                       i_cal_property_take_parameter (property, param);
+                       param = NULL;
+               }
+       } else if (param) {
+               i_cal_property_remove_parameter_by_kind (property, I_CAL_LANGUAGE_PARAMETER);
+       }
+
+       g_clear_object (&param);
+}
+
 /**
  * e_cal_component_text_get_value:
  * @text: an #ECalComponentText
@@ -173,3 +311,44 @@ e_cal_component_text_set_altrep (ECalComponentText *text,
                text->altrep = g_strdup (altrep);
        }
 }
+
+/**
+ * e_cal_component_text_get_language:
+ * @text: an #ECalComponentText
+ *
+ * Returns: the language of the @text
+ *
+ * Since: 3.46
+ **/
+const gchar *
+e_cal_component_text_get_language (const ECalComponentText *text)
+{
+       g_return_val_if_fail (text != NULL, NULL);
+
+       return text->language;
+}
+
+/**
+ * e_cal_component_text_set_language:
+ * @text: an #ECalComponentText
+ * @language: (nullable): language of the @text
+ *
+ * Set the @language as the language of the @text. The language tag
+ * is defined in RFC 5646. For example `en-US`, not `en_US`.
+ *
+ * Since: 3.46
+ **/
+void
+e_cal_component_text_set_language (ECalComponentText *text,
+                                  const gchar *language)
+{
+       g_return_if_fail (text != NULL);
+
+       if (language && !*language)
+               language = NULL;
+
+       if (g_strcmp0 (text->language, language) != 0) {
+               g_free (text->language);
+               text->language = g_strdup (language);
+       }
+}
diff --git a/src/calendar/libecal/e-cal-component-text.h b/src/calendar/libecal/e-cal-component-text.h
index 44044f37e..4d229e87e 100644
--- a/src/calendar/libecal/e-cal-component-text.h
+++ b/src/calendar/libecal/e-cal-component-text.h
@@ -24,6 +24,7 @@
 #define E_CAL_COMPONENT_TEXT_H
 
 #include <glib-object.h>
+#include <libical-glib/libical-glib.h>
 
 G_BEGIN_DECLS
 
@@ -39,15 +40,29 @@ GType               e_cal_component_text_get_type   (void);
 ECalComponentText *
                e_cal_component_text_new        (const gchar *value,
                                                 const gchar *altrep);
+ECalComponentText *
+               e_cal_component_text_new_from_property
+                                               (const ICalProperty *property);
 ECalComponentText *
                e_cal_component_text_copy       (const ECalComponentText *text);
 void           e_cal_component_text_free       (gpointer text); /* ECalComponentText * */
+void           e_cal_component_text_set_from_property
+                                               (ECalComponentText *text,
+                                                const ICalProperty *property);
+void           e_cal_component_text_fill_property
+                                               (const ECalComponentText *text,
+                                                ICalProperty *property);
 const gchar *  e_cal_component_text_get_value  (const ECalComponentText *text);
 void           e_cal_component_text_set_value  (ECalComponentText *text,
                                                 const gchar *value);
 const gchar *  e_cal_component_text_get_altrep (const ECalComponentText *text);
 void           e_cal_component_text_set_altrep (ECalComponentText *text,
                                                 const gchar *altrep);
+const gchar *  e_cal_component_text_get_language
+                                               (const ECalComponentText *text);
+void           e_cal_component_text_set_language
+                                               (ECalComponentText *text,
+                                                const gchar *language);
 
 G_END_DECLS
 
diff --git a/src/calendar/libecal/e-cal-component.c b/src/calendar/libecal/e-cal-component.c
index dd709d2f9..90a7eee5a 100644
--- a/src/calendar/libecal/e-cal-component.c
+++ b/src/calendar/libecal/e-cal-component.c
@@ -182,8 +182,7 @@ static ECalComponentText *
 get_text_from_prop (ICalProperty *prop,
                    const gchar *(* get_prop_func) (ICalProperty *prop))
 {
-       ICalParameter *altrep_param;
-       const gchar *value, *altrep;
+       const gchar *value;
 
        g_return_val_if_fail (prop != NULL, NULL);
        g_return_val_if_fail (get_prop_func != NULL, NULL);
@@ -194,45 +193,27 @@ get_text_from_prop (ICalProperty *prop,
        if (!value || !*value)
                return NULL;
 
-       altrep_param = i_cal_property_get_first_parameter (prop, I_CAL_ALTREP_PARAMETER);
-       altrep = altrep_param ? i_cal_parameter_get_altrep (altrep_param) : NULL;
-       g_clear_object (&altrep_param);
-
-       if (altrep && !*altrep)
-               altrep = NULL;
-
-       return e_cal_component_text_new (value, altrep);
+       return e_cal_component_text_new_from_property (prop);
 }
 
-static void
-set_text_altrep_on_prop (ICalProperty *prop,
-                        const ECalComponentText *text)
+static ECalComponentText *
+get_text_for_locale (ICalComponent *icalcomp,
+                    ICalPropertyKind prop_kind,
+                    const gchar *locale)
 {
-       ICalParameter *param;
-       const gchar *altrep;
-
-       g_return_if_fail (prop != NULL);
-       g_return_if_fail (text != NULL);
+       ECalComponentText *result = NULL;
+       ICalProperty *prop;
 
-       altrep = e_cal_component_text_get_altrep (text);
-       param = i_cal_property_get_first_parameter (prop, I_CAL_ALTREP_PARAMETER);
+       prop = e_cal_util_component_find_property_for_locale (icalcomp, prop_kind, locale);
 
-       if (altrep && *altrep) {
-               if (param) {
-                       i_cal_parameter_set_altrep (param, (gchar *) altrep);
-               } else {
-                       param = i_cal_parameter_new_altrep ((gchar *) altrep);
-                       i_cal_property_take_parameter (prop, param);
-                       param = NULL;
-               }
-       } else if (param) {
-               i_cal_property_remove_parameter_by_kind (prop, I_CAL_ALTREP_PARAMETER);
+       if (prop) {
+               result = e_cal_component_text_new_from_property (prop);
+               g_clear_object (&prop);
        }
 
-       g_clear_object (&param);
+       return result;
 }
 
-
 static void
 cal_component_finalize (GObject *object)
 {
@@ -1291,7 +1272,7 @@ set_text_list (ICalComponent *icalcomp,
 
                prop = new_prop_func ((gchar *) e_cal_component_text_get_value (text));
 
-               set_text_altrep_on_prop (prop, text);
+               e_cal_component_text_fill_property (text, prop);
 
                i_cal_component_take_property (icalcomp, prop);
        }
@@ -1342,6 +1323,33 @@ e_cal_component_set_comments (ECalComponent *comp,
        set_text_list (comp->priv->icalcomp, I_CAL_COMMENT_PROPERTY, i_cal_property_new_comment, text_list);
 }
 
+/**
+ * e_cal_component_dup_comment_for_locale:
+ * @comp: A calendar component object.
+ * @locale: (nullable): a locale identifier, or %NULL
+ *
+ * Returns a comment for the given @locale. When @locale is %NULL,
+ * the current locale is assumed. If no such comment for the locale
+ * exists either a comment with no language parameter or the first
+ * found is returned.
+ *
+ * Free the returned non-NULL #ECalComponentText with e_cal_component_text_free(),
+ * when no longer needed.
+ *
+ * Returns: (transfer full) (nullable): comment for the @locale, %NULL
+ *    if no comment is set on the @comp.
+ *
+ * Since: 3.46
+ **/
+ECalComponentText *
+e_cal_component_dup_comment_for_locale (ECalComponent *comp,
+                                       const gchar *locale)
+{
+       g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), NULL);
+
+       return get_text_for_locale (comp->priv->icalcomp, I_CAL_COMMENT_PROPERTY, locale);
+}
+
 /**
  * e_cal_component_get_contacts:
  * @comp: A calendar component object.
@@ -1549,7 +1557,7 @@ e_cal_component_set_created (ECalComponent *comp,
  * Queries the description of a calendar component object.  Journal components
  * may have more than one description, and as such this function returns a list
  * of #ECalComponentText structures.  All other types of components can have at
- * most one description. Free the returned #GSList with
+ * most one description for a single language. Free the returned #GSList with
  * g_slist_free_full (slist, e_cal_component_text_free);, when no longer needed.
  *
  * Returns: (transfer full) (element-type ECalComponentText) (nullable): the description
@@ -1588,6 +1596,33 @@ e_cal_component_set_descriptions (ECalComponent *comp,
        set_text_list (comp->priv->icalcomp, I_CAL_DESCRIPTION_PROPERTY, i_cal_property_new_description, 
text_list);
 }
 
+/**
+ * e_cal_component_dup_description_for_locale:
+ * @comp: A calendar component object.
+ * @locale: (nullable): a locale identifier, or %NULL
+ *
+ * Returns a description for the given @locale. When @locale is %NULL,
+ * the current locale is assumed. If no such description for the locale
+ * exists either a description with no language parameter or the first
+ * found is returned.
+ *
+ * Free the returned non-NULL #ECalComponentText with e_cal_component_text_free(),
+ * when no longer needed.
+ *
+ * Returns: (transfer full) (nullable): description for the @locale, %NULL
+ *    if no description is set on the @comp.
+ *
+ * Since: 3.46
+ **/
+ECalComponentText *
+e_cal_component_dup_description_for_locale (ECalComponent *comp,
+                                           const gchar *locale)
+{
+       g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), NULL);
+
+       return get_text_for_locale (comp->priv->icalcomp, I_CAL_DESCRIPTION_PROPERTY, locale);
+}
+
 /* Gets a date/time and timezone pair */
 static ECalComponentDateTime *
 get_datetime (ICalComponent *icalcomp,
@@ -3446,7 +3481,10 @@ e_cal_component_set_status (ECalComponent *comp,
  * e_cal_component_get_summary:
  * @comp: A calendar component object.
  *
- * Queries the summary of a calendar component object.
+ * Queries the summary of a calendar component object. It returns the first
+ * found summary property of the component. To get a summary suitable for a specific
+ * locale use e_cal_component_dup_summary_for_locale().
+ *
  * Free the returned pointer withe_cal_component_text_free(),
  * when no longer needed.
  *
@@ -3537,6 +3575,8 @@ set_alarm_description_cb (ICalComponent *icalcomp,
  *
  * Sets the summary of a calendar component object.
  *
+ * This also updates any alarm subcomponent descriptions, if needed.
+ *
  * Since: 3.34
  **/
 void
@@ -3544,23 +3584,29 @@ e_cal_component_set_summary (ECalComponent *comp,
                             const ECalComponentText *summary)
 {
        ICalProperty *prop;
+       GSList *to_remove, *link;
        SetAlarmDescriptionData sadd;
 
        g_return_if_fail (E_IS_CAL_COMPONENT (comp));
        g_return_if_fail (comp->priv->icalcomp != NULL);
 
-       prop = i_cal_component_get_first_property (comp->priv->icalcomp, I_CAL_SUMMARY_PROPERTY);
+       to_remove = gather_all_properties (comp->priv->icalcomp, I_CAL_SUMMARY_PROPERTY, FALSE);
+
+       prop = to_remove ? to_remove->data : NULL;
 
        if (!summary) {
-               if (prop) {
+               for (link = to_remove; link; link = g_slist_next (link)) {
+                       prop = link->data;
+
                        i_cal_component_remove_property (comp->priv->icalcomp, prop);
-                       g_object_unref (prop);
                }
 
+               g_slist_free_full (to_remove, g_object_unref);
                return;
        }
 
        if (!e_cal_component_text_get_value (summary)) {
+               g_slist_free_full (to_remove, g_object_unref);
                g_clear_object (&prop);
                return;
        }
@@ -3569,16 +3615,22 @@ e_cal_component_set_summary (ECalComponent *comp,
                /* Make a copy, to avoid use-after-free */
                sadd.old_summary = g_strdup (i_cal_property_get_summary (prop));
                i_cal_property_set_summary (prop, (gchar *) e_cal_component_text_get_value (summary));
-               set_text_altrep_on_prop (prop, summary);
+               e_cal_component_text_fill_property (summary, prop);
        } else {
                sadd.old_summary = NULL;
                prop = i_cal_property_new_summary ((gchar *) e_cal_component_text_get_value (summary));
-               set_text_altrep_on_prop (prop, summary);
+               e_cal_component_text_fill_property (summary, prop);
                i_cal_component_take_property (comp->priv->icalcomp, prop);
                prop = NULL;
        }
 
-       g_clear_object (&prop);
+       /* Skip the first, because it had been re-used */
+       for (link = to_remove ? to_remove->next : NULL; link; link = g_slist_next (link)) {
+               prop = link->data;
+               i_cal_component_remove_property (comp->priv->icalcomp, prop);
+       }
+
+       g_slist_free_full (to_remove, g_object_unref);
 
        /* look for alarms that need a description */
        sadd.new_summary = e_cal_component_text_get_value (summary);
@@ -3588,6 +3640,77 @@ e_cal_component_set_summary (ECalComponent *comp,
        g_free (sadd.old_summary);
 }
 
+/**
+ * e_cal_component_dup_summaries:
+ * @comp: A calendar component object.
+ *
+ * Queries the summary of a calendar component object. There can be one summary
+ * property per locale. Free the returned #GSList with
+ * g_slist_free_full (slist, e_cal_component_text_free);, when no longer needed.
+ *
+ * Returns: (transfer full) (element-type ECalComponentText) (nullable): the summary
+ *    properties and their parameters, as a #GSList of #ECalComponentText structures.
+ *
+ * Since: 3.46
+ **/
+GSList *
+e_cal_component_dup_summaries (ECalComponent *comp)
+{
+       g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), NULL);
+       g_return_val_if_fail (comp->priv->icalcomp != NULL, NULL);
+
+       return get_text_list (comp->priv->icalcomp, I_CAL_SUMMARY_PROPERTY, i_cal_property_get_summary);
+}
+
+/**
+ * e_cal_component_set_summaries:
+ * @comp: A calendar component object.
+ * @text_list: (element-type ECalComponentText): List of #ECalComponentText structures.
+ *
+ * Sets the summary of a calendar component object. The summaries can have each
+ * different language, otherwise it's not allowed to have more than one summary property.
+ *
+ * This does not update any alarm subcomponent description.
+ *
+ * Since: 3.46
+ **/
+void
+e_cal_component_set_summaries (ECalComponent *comp,
+                              const GSList *text_list)
+{
+       g_return_if_fail (E_IS_CAL_COMPONENT (comp));
+       g_return_if_fail (comp->priv->icalcomp != NULL);
+
+       set_text_list (comp->priv->icalcomp, I_CAL_SUMMARY_PROPERTY, i_cal_property_new_summary, text_list);
+}
+
+/**
+ * e_cal_component_dup_summary_for_locale:
+ * @comp: A calendar component object.
+ * @locale: (nullable): a locale identifier, or %NULL
+ *
+ * Returns a summary for the given @locale. When @locale is %NULL,
+ * the current locale is assumed. If no such summary for the locale
+ * exists either a summary with no language parameter or the first
+ * found is returned.
+ *
+ * Free the returned non-NULL #ECalComponentText with e_cal_component_text_free(),
+ * when no longer needed.
+ *
+ * Returns: (transfer full) (nullable): summary for the @locale, %NULL
+ *    if no summary is set on the @comp.
+ *
+ * Since: 3.46
+ **/
+ECalComponentText *
+e_cal_component_dup_summary_for_locale (ECalComponent *comp,
+                                       const gchar *locale)
+{
+       g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), NULL);
+
+       return get_text_for_locale (comp->priv->icalcomp, I_CAL_SUMMARY_PROPERTY, locale);
+}
+
 /**
  * e_cal_component_get_transparency:
  * @comp: A calendar component object.
diff --git a/src/calendar/libecal/e-cal-component.h b/src/calendar/libecal/e-cal-component.h
index 2ef22ecea..2a8ad6160 100644
--- a/src/calendar/libecal/e-cal-component.h
+++ b/src/calendar/libecal/e-cal-component.h
@@ -131,6 +131,10 @@ void               e_cal_component_set_classification
 GSList *       e_cal_component_get_comments    (ECalComponent *comp); /* ECalComponentText * */
 void           e_cal_component_set_comments    (ECalComponent *comp,
                                                 const GSList *text_list); /* ECalComponentText * */
+ECalComponentText *
+               e_cal_component_dup_comment_for_locale
+                                               (ECalComponent *comp,
+                                                const gchar *locale);
 
 ICalTime *     e_cal_component_get_completed   (ECalComponent *comp);
 void           e_cal_component_set_completed   (ECalComponent *comp,
@@ -147,6 +151,10 @@ void               e_cal_component_set_created     (ECalComponent *comp,
 GSList *       e_cal_component_get_descriptions(ECalComponent *comp);  /* ECalComponentText * */
 void           e_cal_component_set_descriptions(ECalComponent *comp,
                                                 const GSList *text_list); /* ECalComponentText * */
+ECalComponentText *
+               e_cal_component_dup_description_for_locale
+                                               (ECalComponent *comp,
+                                                const gchar *locale);
 
 ECalComponentDateTime *
                e_cal_component_get_dtend       (ECalComponent *comp);
@@ -244,6 +252,13 @@ ECalComponentText *
                e_cal_component_get_summary     (ECalComponent *comp);
 void           e_cal_component_set_summary     (ECalComponent *comp,
                                                 const ECalComponentText *summary);
+GSList *       e_cal_component_dup_summaries   (ECalComponent *comp);
+void           e_cal_component_set_summaries   (ECalComponent *comp,
+                                                const GSList *text_list);
+ECalComponentText *
+               e_cal_component_dup_summary_for_locale
+                                               (ECalComponent *comp,
+                                                const gchar *locale);
 
 ECalComponentTransparency
                e_cal_component_get_transparency(ECalComponent *comp);
diff --git a/src/calendar/libecal/e-cal-util.c b/src/calendar/libecal/e-cal-util.c
index fed67ffae..6903069e4 100644
--- a/src/calendar/libecal/e-cal-util.c
+++ b/src/calendar/libecal/e-cal-util.c
@@ -3190,3 +3190,129 @@ e_cal_util_clamp_vtimezone_by_component (ICalComponent *vtimezone,
        g_clear_object (&dtstart);
        g_clear_object (&dtend);
 }
+
+static gboolean
+locale_equals_language (const gchar *locale,
+                       const gchar *language)
+{
+       guint ii;
+
+       for (ii = 0; locale[ii] && language[ii]; ii++) {
+               if ((locale[ii] == '-' || locale[ii] == '_') &&
+                   (language[ii] == '-' || language[ii] == '_')) {
+                       continue;
+               }
+
+               if (g_ascii_tolower (locale[ii]) != g_ascii_tolower (language[ii]))
+                       break;
+       }
+
+       return !locale[ii] && !language[ii];
+}
+
+/**
+ * e_cal_util_component_find_property_for_locale:
+ * @icalcomp: an #ICalComponent
+ * @prop_kind: an #ICalPropertyKind to traverse
+ * @locale: (nullable): a locale identifier, or %NULL
+ *
+ * Searches properties of kind @prop_kind in the @icalcomp and returns
+ * one, which is usable for the @locale. When @locale is %NULL,
+ * the current locale is assumed. If no such property for the locale
+ * exists either the one with no language parameter or the first
+ * found is returned.
+ *
+ * Free the returned non-NULL #ICalProperty with g_object_unref(),
+ * when no longer needed.
+ *
+ * Returns: (transfer full) (nullable): a property of kind @prop_kind for the @locale,
+ *    %NULL if no such property is set on the @comp.
+ *
+ * Since: 3.46
+
+ **/
+ICalProperty *
+e_cal_util_component_find_property_for_locale (ICalComponent *icalcomp,
+                                              ICalPropertyKind prop_kind,
+                                              const gchar *locale)
+{
+       ICalProperty *prop;
+       ICalProperty *result = NULL;
+       ICalProperty *first = NULL;
+       ICalProperty *nolang = NULL;
+       ICalProperty *best = NULL;
+       gint best_index = -1;
+       gchar **locale_variants = NULL;
+       const gchar *const *locales = NULL;
+
+       g_return_val_if_fail (I_CAL_IS_COMPONENT (icalcomp), NULL);
+
+       if (locale) {
+               locale_variants = g_get_locale_variants (locale);
+               locales = (const gchar * const *) locale_variants;
+       }
+
+       if (!locales)
+               locales = g_get_language_names ();
+
+       for (prop = i_cal_component_get_first_property (icalcomp, prop_kind);
+            prop;
+            g_object_unref (prop), prop = i_cal_component_get_next_property (icalcomp, prop_kind)) {
+               ICalParameter *param;
+
+               param = i_cal_property_get_first_parameter (prop, I_CAL_LANGUAGE_PARAMETER);
+               if (param) {
+                       const gchar *language = i_cal_parameter_get_language (param);
+
+                       if (!language || !*language) {
+                               if (!best) {
+                                       if (!first)
+                                               first = g_object_ref (prop);
+                                       if (!nolang)
+                                               nolang = g_object_ref (prop);
+                               }
+                       } else {
+                               guint ii;
+
+                               for (ii = 0; locales && locales[ii] && (best_index == -1 || ii < best_index); 
ii++) {
+                                       if (locale_equals_language (locales[ii], language)) {
+                                               g_clear_object (&best);
+                                               best = g_object_ref (prop);
+                                               best_index = ii;
+                                               break;
+                                       }
+                               }
+
+                               if (!ii && best) {
+                                       g_clear_object (&param);
+                                       g_clear_object (&prop);
+                                       break;
+                               }
+
+                               if (!best && !first)
+                                       first = g_object_ref (prop);
+                       }
+
+                       g_clear_object (&param);
+               } else if (!best) {
+                       if (!first)
+                               first = g_object_ref (prop);
+                       if (!nolang)
+                               nolang = g_object_ref (prop);
+               }
+       }
+
+       if (best)
+               result = g_steal_pointer (&best);
+       else if (nolang)
+               result = g_steal_pointer (&nolang);
+       else if (first)
+               result = g_steal_pointer (&first);
+
+       g_clear_object (&first);
+       g_clear_object (&nolang);
+       g_clear_object (&best);
+       g_clear_pointer (&locale_variants, g_strfreev);
+
+       return result;
+}
diff --git a/src/calendar/libecal/e-cal-util.h b/src/calendar/libecal/e-cal-util.h
index 540812263..bf79bf41d 100644
--- a/src/calendar/libecal/e-cal-util.h
+++ b/src/calendar/libecal/e-cal-util.h
@@ -378,6 +378,10 @@ void               e_cal_util_clamp_vtimezone      (ICalComponent *vtimezone,
 void           e_cal_util_clamp_vtimezone_by_component
                                                (ICalComponent *vtimezone,
                                                 ICalComponent *component);
+ICalProperty * e_cal_util_component_find_property_for_locale
+                                               (ICalComponent *icalcomp,
+                                                ICalPropertyKind prop_kind,
+                                                const gchar *locale);
 
 G_END_DECLS
 
diff --git a/tests/libecal/test-cal-component.c b/tests/libecal/test-cal-component.c
index 2b8146662..0220d4f5b 100644
--- a/tests/libecal/test-cal-component.c
+++ b/tests/libecal/test-cal-component.c
@@ -348,6 +348,7 @@ verify_struct_text_equal (const ECalComponentText *expected,
 
        g_assert_cmpstr (e_cal_component_text_get_value (expected), ==, e_cal_component_text_get_value 
(received));
        g_assert_cmpstr (e_cal_component_text_get_altrep (expected), ==, e_cal_component_text_get_altrep 
(received));
+       g_assert_cmpstr (e_cal_component_text_get_language (expected), ==, e_cal_component_text_get_language 
(received));
 }
 
 static void
@@ -1524,7 +1525,7 @@ static void
 test_component_struct_parameter_bag (void)
 {
        const gchar *prop_str =
-               "ATTENDEE;CHARSET=utf-8;CN=User;CUTYPE=INDIVIDUAL;" X_PARAM_NAME "=" X_PARAM_VALUE 
";LANGUAGE=en_US:mailto:user@no.where";;
+               "ATTENDEE;CHARSET=utf-8;CN=User;CUTYPE=INDIVIDUAL;" X_PARAM_NAME "=" X_PARAM_VALUE 
";LANGUAGE=en-US:mailto:user@no.where";;
        ICalParameterKind expected_unfiltered[] = {
                I_CAL_CHARSET_PARAMETER,
                I_CAL_CN_PARAMETER,
@@ -2078,17 +2079,24 @@ test_component_struct_text (void)
        struct _values {
                const gchar *value;
                const gchar *altrep;
+               const gchar *language;
        } values[] = {
-               { "value1", NULL },
-               { "value2", "altrep1" },
-               { "value3", "altrep2" },
-               { "value4", NULL }
+               { "value1", NULL, NULL },
+               { "value2", "altrep1", NULL },
+               { "value3", "altrep2", NULL },
+               { "value4", NULL, NULL },
+               { "value1", NULL, "en_US" },
+               { "value2", "altrep1", "en" },
+               { "value3", "altrep2", "en_GB" },
+               { "value4", NULL, "en" }
        };
+       ICalProperty *prop;
+       ECalComponentText *expected, *received;
        gint ii, set_kind;
 
        for (set_kind = 0; set_kind < 3; set_kind++) {
                for (ii = 0; ii < G_N_ELEMENTS (values); ii++) {
-                       ECalComponentText *expected = NULL, *received;
+                       expected = NULL;
 
                        if (set_kind == 1) {
                                expected = e_cal_component_text_new ("non-empty", NULL);
@@ -2099,13 +2107,16 @@ test_component_struct_text (void)
                        if (expected) {
                                e_cal_component_text_set_value (expected, values[ii].value);
                                e_cal_component_text_set_altrep (expected, values[ii].altrep);
+                               e_cal_component_text_set_language (expected, values[ii].language);
                        } else {
                                expected = e_cal_component_text_new (values[ii].value, values[ii].altrep);
+                               e_cal_component_text_set_language (expected, values[ii].language);
                        }
 
                        g_assert_nonnull (expected);
                        g_assert_cmpstr (e_cal_component_text_get_value (expected), ==, values[ii].value);
                        g_assert_cmpstr (e_cal_component_text_get_altrep (expected), ==, values[ii].altrep);
+                       g_assert_cmpstr (e_cal_component_text_get_language (expected), ==, 
values[ii].language);
 
                        received = e_cal_component_text_copy (expected);
                        verify_struct_text_equal (expected, received);
@@ -2114,6 +2125,64 @@ test_component_struct_text (void)
                        e_cal_component_text_free (expected);
                }
        }
+
+       prop = i_cal_property_new_summary ("summary1");
+
+       expected = e_cal_component_text_new ("summary1", NULL);
+
+       received = e_cal_component_text_new_from_property (prop);
+       g_assert_nonnull (received);
+       g_assert_cmpstr (e_cal_component_text_get_value (received), ==, "summary1");
+       g_assert_null (e_cal_component_text_get_altrep (received));
+       g_assert_null (e_cal_component_text_get_language (received));
+       verify_struct_text_equal (expected, received);
+
+       e_cal_component_text_set_value (expected, "summary2");
+       e_cal_component_text_set_altrep (expected, "altrep");
+       e_cal_component_text_fill_property (expected, prop);
+
+       e_cal_component_text_set_from_property (received, prop);
+       g_assert_cmpstr (e_cal_component_text_get_value (received), ==, "summary2");
+       g_assert_cmpstr (e_cal_component_text_get_altrep (received), ==, "altrep");
+       g_assert_null (e_cal_component_text_get_language (received));
+       verify_struct_text_equal (expected, received);
+
+       e_cal_component_text_set_value (expected, "summary3");
+       e_cal_component_text_set_altrep (expected, NULL);
+       e_cal_component_text_set_language (expected, "en");
+       e_cal_component_text_fill_property (expected, prop);
+
+       e_cal_component_text_set_from_property (received, prop);
+       g_assert_cmpstr (e_cal_component_text_get_value (received), ==, "summary3");
+       g_assert_null (e_cal_component_text_get_altrep (received));
+       g_assert_cmpstr (e_cal_component_text_get_language (received), ==, "en");
+       verify_struct_text_equal (expected, received);
+
+       e_cal_component_text_set_value (expected, "summary4");
+       e_cal_component_text_set_altrep (expected, "altrep2");
+       e_cal_component_text_set_language (expected, "en_GB");
+       e_cal_component_text_fill_property (expected, prop);
+
+       e_cal_component_text_set_from_property (received, prop);
+       g_assert_cmpstr (e_cal_component_text_get_value (received), ==, "summary4");
+       g_assert_cmpstr (e_cal_component_text_get_altrep (received), ==, "altrep2");
+       g_assert_cmpstr (e_cal_component_text_get_language (received), ==, "en_GB");
+       verify_struct_text_equal (expected, received);
+
+       e_cal_component_text_set_value (expected, "summary5");
+       e_cal_component_text_set_altrep (expected, NULL);
+       e_cal_component_text_set_language (expected, NULL);
+       e_cal_component_text_fill_property (expected, prop);
+
+       e_cal_component_text_set_from_property (received, prop);
+       g_assert_cmpstr (e_cal_component_text_get_value (received), ==, "summary5");
+       g_assert_null (e_cal_component_text_get_altrep (received));
+       g_assert_null (e_cal_component_text_get_language (received));
+       verify_struct_text_equal (expected, received);
+
+       e_cal_component_text_free (received);
+       e_cal_component_text_free (expected);
+       g_clear_object (&prop);
 }
 
 static void
@@ -2364,16 +2433,30 @@ test_split_texts (const gchar *value)
        if (textsv) {
                for (ii = 0; textsv[ii]; ii++) {
                        ECalComponentText *comptext;
-                       gchar *altrep;
+                       gchar *altrep, *language = NULL;
 
                        altrep = strchr (textsv[ii], '|');
                        if (altrep) {
                                *altrep = '\0';
                                altrep++;
+
+                               language = strchr (altrep, '|');
+                               if (language) {
+                                       *language = '\0';
+                                       language++;
+
+                                       if (!*language)
+                                               language = NULL;
+                               }
+
+                               if (!*altrep)
+                                       altrep = NULL;
                        }
 
                        comptext = e_cal_component_text_new (textsv[ii], altrep);
                        g_assert_nonnull (comptext);
+                       if (language)
+                               e_cal_component_text_set_language (comptext, language);
                        result = g_slist_prepend (result, comptext);
                }
 
@@ -2424,6 +2507,10 @@ test_component_text_list (void (* set_func) (ECalComponent *comp,
                "line1\nline2|altrep",
                "text|altrep",
                "text1:text2|altrep2:text3a\ntext3b|altrep3",
+               "text||en",
+               "line1\nline2|altrep|en_US",
+               "text|altrep|en_GB",
+               "text1:text2|altrep2|en_GB:text3a\ntext3b|altrep3|en",
                NULL
        };
        ECalComponent *comp;
@@ -2726,6 +2813,64 @@ test_component_comments (void)
        test_component_text_list (e_cal_component_set_comments, verify_component_comments);
 }
 
+static void
+test_component_comments_locale (void)
+{
+       const gchar *comp_str =
+               "BEGIN:VEVENT\r\n"
+               "UID:1\r\n"
+               "COMMENT;LANGUAGE=en-US:desc-en-US\r\n"
+               "COMMENT;LANGUAGE=en:desc-en\r\n"
+               "COMMENT;LANGUAGE=en-GB:desc-en-GB\r\n"
+               "COMMENT:desc\r\n"
+               "END:VEVENT\r\n";
+       ECalComponent *comp;
+       ECalComponentText *text;
+
+       comp = e_cal_component_new_from_string (comp_str);
+       g_assert_nonnull (comp);
+
+       text = e_cal_component_dup_comment_for_locale (comp, NULL);
+       g_assert_nonnull (text);
+       e_cal_component_text_free (text);
+
+       text = e_cal_component_dup_comment_for_locale (comp, "en_US");
+       g_assert_cmpstr (e_cal_component_text_get_value (text), ==, "desc-en-US");
+       e_cal_component_text_free (text);
+
+       text = e_cal_component_dup_comment_for_locale (comp, "en_GB");
+       g_assert_cmpstr (e_cal_component_text_get_value (text), ==, "desc-en-GB");
+       e_cal_component_text_free (text);
+
+       text = e_cal_component_dup_comment_for_locale (comp, "en");
+       g_assert_cmpstr (e_cal_component_text_get_value (text), ==, "desc-en");
+       e_cal_component_text_free (text);
+
+       text = e_cal_component_dup_comment_for_locale (comp, "xxx");
+       g_assert_cmpstr (e_cal_component_text_get_value (text), ==, "desc");
+       e_cal_component_text_free (text);
+
+       g_clear_object (&comp);
+
+       comp_str =
+               "BEGIN:VEVENT\r\n"
+               "UID:1\r\n"
+               "COMMENT;LANGUAGE=en-US:desc-en-US\r\n"
+               "COMMENT;LANGUAGE=en:desc-en\r\n"
+               "COMMENT;LANGUAGE=en-GB:desc-en-GB\r\n"
+               "END:VEVENT\r\n";
+
+       comp = e_cal_component_new_from_string (comp_str);
+       g_assert_nonnull (comp);
+
+       text = e_cal_component_dup_comment_for_locale (comp, "xxx");
+       g_assert_nonnull (text);
+       g_assert_cmpstr (e_cal_component_text_get_value (text), ==, "desc-en-US");
+       e_cal_component_text_free (text);
+
+       g_clear_object (&comp);
+}
+
 static void
 verify_component_completed (ECalComponent *comp,
                            gpointer user_data)
@@ -2778,6 +2923,64 @@ test_component_descriptions (void)
        test_component_text_list (e_cal_component_set_descriptions, verify_component_descriptions);
 }
 
+static void
+test_component_descriptions_locale (void)
+{
+       const gchar *comp_str =
+               "BEGIN:VEVENT\r\n"
+               "UID:1\r\n"
+               "DESCRIPTION;LANGUAGE=en-US:desc-en-US\r\n"
+               "DESCRIPTION;LANGUAGE=en:desc-en\r\n"
+               "DESCRIPTION;LANGUAGE=en-GB:desc-en-GB\r\n"
+               "DESCRIPTION:desc\r\n"
+               "END:VEVENT\r\n";
+       ECalComponent *comp;
+       ECalComponentText *text;
+
+       comp = e_cal_component_new_from_string (comp_str);
+       g_assert_nonnull (comp);
+
+       text = e_cal_component_dup_description_for_locale (comp, NULL);
+       g_assert_nonnull (text);
+       e_cal_component_text_free (text);
+
+       text = e_cal_component_dup_description_for_locale (comp, "en_US");
+       g_assert_cmpstr (e_cal_component_text_get_value (text), ==, "desc-en-US");
+       e_cal_component_text_free (text);
+
+       text = e_cal_component_dup_description_for_locale (comp, "en_GB");
+       g_assert_cmpstr (e_cal_component_text_get_value (text), ==, "desc-en-GB");
+       e_cal_component_text_free (text);
+
+       text = e_cal_component_dup_description_for_locale (comp, "en");
+       g_assert_cmpstr (e_cal_component_text_get_value (text), ==, "desc-en");
+       e_cal_component_text_free (text);
+
+       text = e_cal_component_dup_description_for_locale (comp, "xxx");
+       g_assert_cmpstr (e_cal_component_text_get_value (text), ==, "desc");
+       e_cal_component_text_free (text);
+
+       g_clear_object (&comp);
+
+       comp_str =
+               "BEGIN:VEVENT\r\n"
+               "UID:1\r\n"
+               "DESCRIPTION;LANGUAGE=en-US:desc-en-US\r\n"
+               "DESCRIPTION;LANGUAGE=en:desc-en\r\n"
+               "DESCRIPTION;LANGUAGE=en-GB:desc-en-GB\r\n"
+               "END:VEVENT\r\n";
+
+       comp = e_cal_component_new_from_string (comp_str);
+       g_assert_nonnull (comp);
+
+       text = e_cal_component_dup_description_for_locale (comp, "xxx");
+       g_assert_nonnull (text);
+       g_assert_cmpstr (e_cal_component_text_get_value (text), ==, "desc-en-US");
+       e_cal_component_text_free (text);
+
+       g_clear_object (&comp);
+}
+
 static void
 verify_component_dtend (ECalComponent *comp,
                        gpointer user_data)
@@ -3420,7 +3623,11 @@ test_component_summary (void)
                "line1\nline2|altrep",
                "text|altrep",
                NULL,
-               "text1:text2|altrep2:text3a\ntext3b|altrep3"
+               "text1:text2|altrep2:text3a\ntext3b|altrep3",
+               "text||en",
+               "line1\nline2|altrep|en_US",
+               "text|altrep|en_GB",
+               "text1:text2|altrep2|en:text3a\ntext3b|altrep3|en_US"
        };
        ECalComponent *comp;
        gint ii;
@@ -3449,6 +3656,107 @@ test_component_summary (void)
        g_object_unref (comp);
 }
 
+static void
+test_component_summary_locale (void)
+{
+       const gchar *comp_str =
+               "BEGIN:VEVENT\r\n"
+               "UID:1\r\n"
+               "SUMMARY;LANGUAGE=en-US:summ-en-US\r\n"
+               "SUMMARY;LANGUAGE=en:summ-en\r\n"
+               "SUMMARY;LANGUAGE=en-GB:summ-en-GB\r\n"
+               "SUMMARY:summ\r\n"
+               "END:VEVENT\r\n";
+       ECalComponent *comp;
+       ECalComponentText *text;
+
+       comp = e_cal_component_new_from_string (comp_str);
+       g_assert_nonnull (comp);
+
+       text = e_cal_component_dup_summary_for_locale (comp, NULL);
+       g_assert_nonnull (text);
+       e_cal_component_text_free (text);
+
+       text = e_cal_component_dup_summary_for_locale (comp, "en_US");
+       g_assert_cmpstr (e_cal_component_text_get_value (text), ==, "summ-en-US");
+       e_cal_component_text_free (text);
+
+       text = e_cal_component_dup_summary_for_locale (comp, "en_GB");
+       g_assert_cmpstr (e_cal_component_text_get_value (text), ==, "summ-en-GB");
+       e_cal_component_text_free (text);
+
+       text = e_cal_component_dup_summary_for_locale (comp, "en");
+       g_assert_cmpstr (e_cal_component_text_get_value (text), ==, "summ-en");
+       e_cal_component_text_free (text);
+
+       text = e_cal_component_dup_summary_for_locale (comp, "xxx");
+       g_assert_cmpstr (e_cal_component_text_get_value (text), ==, "summ");
+       e_cal_component_text_free (text);
+
+       g_clear_object (&comp);
+
+       comp_str =
+               "BEGIN:VEVENT\r\n"
+               "UID:1\r\n"
+               "SUMMARY;LANGUAGE=en-US:summ-en-US\r\n"
+               "SUMMARY;LANGUAGE=en:summ-en\r\n"
+               "SUMMARY;LANGUAGE=en-GB:summ-en-GB\r\n"
+               "END:VEVENT\r\n";
+
+       comp = e_cal_component_new_from_string (comp_str);
+       g_assert_nonnull (comp);
+
+       text = e_cal_component_dup_summary_for_locale (comp, "xxx");
+       g_assert_nonnull (text);
+       g_assert_cmpstr (e_cal_component_text_get_value (text), ==, "summ-en-US");
+       e_cal_component_text_free (text);
+
+       g_clear_object (&comp);
+}
+
+static void
+verify_component_summaries (ECalComponent *comp,
+                           gpointer user_data)
+{
+       verify_component_text_list (e_cal_component_dup_summaries, comp, user_data);
+}
+
+static void
+test_component_summaries (void)
+{
+       const gchar *comp_str =
+               "BEGIN:VEVENT\r\n"
+               "UID:1\r\n"
+               "SUMMARY;LANGUAGE=en-US:summ-en-US\r\n"
+               "SUMMARY;LANGUAGE=en:summ-en\r\n"
+               "SUMMARY;LANGUAGE=en-GB:summ-en-GB\r\n"
+               "SUMMARY:summ\r\n"
+               "END:VEVENT\r\n";
+       ECalComponent *comp;
+       ECalComponentText *text;
+       GSList *slist1, *slist2;
+
+       comp = e_cal_component_new_from_string (comp_str);
+       g_assert_nonnull (comp);
+
+       slist1 = e_cal_component_dup_summaries (comp);
+       g_assert_cmpint (g_slist_length (slist1), ==, 4);
+
+       text = e_cal_component_text_new ("summary", NULL);
+       e_cal_component_set_summary (comp, text);
+       slist2 = e_cal_component_dup_summaries (comp);
+       g_assert_cmpint (g_slist_length (slist2), ==, 1);
+       verify_struct_text_equal (text, slist2->data);
+       g_slist_free_full (slist2, e_cal_component_text_free);
+       e_cal_component_text_free (text);
+
+       e_cal_component_set_summaries (comp, slist1);
+       verify_changes (comp, verify_component_summaries, slist1);
+
+       g_slist_free_full (slist1, e_cal_component_text_free);
+       g_clear_object (&comp);
+}
+
 static void
 verify_component_transparency (ECalComponent *comp,
                               gpointer user_data)
@@ -4019,10 +4327,12 @@ main (gint argc,
        g_test_add_func ("/ECalComponent/categories", test_component_categories);
        g_test_add_func ("/ECalComponent/classification", test_component_classification);
        g_test_add_func ("/ECalComponent/comments", test_component_comments);
+       g_test_add_func ("/ECalComponent/comments-locale", test_component_comments_locale);
        g_test_add_func ("/ECalComponent/completed", test_component_completed);
        g_test_add_func ("/ECalComponent/contacts", test_component_contacts);
        g_test_add_func ("/ECalComponent/created", test_component_created);
        g_test_add_func ("/ECalComponent/descriptions", test_component_descriptions);
+       g_test_add_func ("/ECalComponent/descriptions-locale", test_component_descriptions_locale);
        g_test_add_func ("/ECalComponent/dtend", test_component_dtend);
        g_test_add_func ("/ECalComponent/dtstamp", test_component_dtstamp);
        g_test_add_func ("/ECalComponent/dtstart", test_component_dtstart);
@@ -4040,6 +4350,8 @@ main (gint argc,
        g_test_add_func ("/ECalComponent/sequence", test_component_sequence);
        g_test_add_func ("/ECalComponent/status", test_component_status);
        g_test_add_func ("/ECalComponent/summary", test_component_summary);
+       g_test_add_func ("/ECalComponent/summaries", test_component_summaries);
+       g_test_add_func ("/ECalComponent/summary-locale", test_component_summary_locale);
        g_test_add_func ("/ECalComponent/transparency", test_component_transparency);
        g_test_add_func ("/ECalComponent/url", test_component_url);
        g_test_add_func ("/ECalComponent/attendees", test_component_attendees);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]