diff --git a/cgi/product_multilingual.pl b/cgi/product_multilingual.pl
index a84a220a3baf3..37d16ed96a65b 100755
--- a/cgi/product_multilingual.pl
+++ b/cgi/product_multilingual.pl
@@ -1052,9 +1052,10 @@ ($$$$$)
# this needs to be below the "add (language name) in all field labels" above, so that it does not change this label.
if (($User{moderator}) and ($tabsid eq "front_image")) {
- my $msg = sprintf(lang("move_data_and_photos_to_main_language"),
- '' . $language . '',
- '' . lang("lang_" . $product_ref->{lc}) . '');
+ my $msg = f_lang("f_move_data_and_photos_to_main_language", {
+ language => '' . $language . '',
+ main_language => '' . lang("lang_" . $product_ref->{lc}) . ''
+ });
my $moveid = "move_" . $tabid . "_data_and_images_to_main_language";
diff --git a/lib/ProductOpener/Display.pm b/lib/ProductOpener/Display.pm
index d2cb75974e87b..2a16a1e3b022b 100644
--- a/lib/ProductOpener/Display.pm
+++ b/lib/ProductOpener/Display.pm
@@ -380,6 +380,7 @@ sub process_template($$$) {
$template_data_ref->{pro_moderator} = $User{pro_moderator};
$template_data_ref->{sep} = separator_before_colon($lc);
$template_data_ref->{lang} = \〈
+ $template_data_ref->{f_lang} = \&f_lang;
$template_data_ref->{lang_sprintf} = \&lang_sprintf;
$template_data_ref->{lc} = $lc;
$template_data_ref->{cc} = $cc;
diff --git a/lib/ProductOpener/Lang.pm b/lib/ProductOpener/Lang.pm
index 776a43b6f8e45..593b5c1661658 100644
--- a/lib/ProductOpener/Lang.pm
+++ b/lib/ProductOpener/Lang.pm
@@ -58,6 +58,7 @@ BEGIN
&lang
&lang_sprintf
+ &f_lang
&lang_in_other_lc
%lang_lc
@@ -113,7 +114,7 @@ sub separator_before_colon($) {
Returns a translation for a specific string id in the language defined in the $lang global variable.
-If a translation is not available, returns English.
+If a translation is not available, the function returns English.
=head3 Arguments
@@ -157,7 +158,10 @@ in the language defined in the $lang global variable.
The translation is stored using the sprintf format (e.g. with %s) and
lang_sprintf() calls sprintf() to process it.
-If a translation is not available, returns English.
+Warning: if multiple variables need to be interpolated,
+they will be in the same order for all languages.
+
+If a translation is not available, the function returns English.
=head3 Arguments
@@ -165,6 +169,10 @@ If a translation is not available, returns English.
In the .po translation files, we use the msgctxt field for the string id.
+=head4 other arguments
+
+Arguments to be interpolated.
+
=cut
sub lang_sprintf() {
@@ -181,11 +189,52 @@ sub lang_sprintf() {
}
+=head2 f_lang( $stringid, $variables_ref )
+
+Returns a translation for a specific string id with specific arguments
+in the language defined in the $lang global variable.
+
+The translation is stored using Python's f-string format with
+named parameters between { }.
+
+e.g. "This is a string with {a_variable} and {another_variable}."
+
+Variables between { } are interpolated with the corresponding entry
+in the $variables_ref hash reference.
+
+If a translation is not available, the function returns English.
+
+=head3 Arguments
+
+=head4 string id $stringid
+
+In the .po translation files, we use the msgctxt field for the string id.
+
+=cut
+
+sub f_lang($$) {
+
+ my $stringid = shift;
+ my $variables_ref = shift;
+
+ my $translation = lang($stringid);
+ if (defined $translation) {
+ # look for string keys between { } and replace them with the corresponding
+ # value in $variables_ref hash reference
+ $translation =~ s/\{([^\{\}]+)\}/$variables_ref->{$1}/eg;
+ return $translation;
+ }
+ else {
+ return '';
+ }
+}
+
+
=head2 lang_in_other_lc( $target_lc, $stringid )
Returns a translation for a specific string id in a specific language.
-If a translation is not available, returns English.
+If a translation is not available, the function returns English.
=head3 Arguments
diff --git a/po/common/common.pot b/po/common/common.pot
index c9dd92a5c10be..1c9c424aec64f 100644
--- a/po/common/common.pot
+++ b/po/common/common.pot
@@ -4305,10 +4305,10 @@ msgctxt "some_unknown_ingredients"
msgid "Some ingredients could not be recognized."
msgstr "Some ingredients could not be recognized."
-# keep the 2 %s : they will be replaced by language names.
-msgctxt "move_data_and_photos_to_main_language"
-msgid "Move all data and selected photos in %s to the main language of the product: %s"
-msgstr "Move all data and selected photos in %s to the main language of the product: %s"
+# variable names between { } must not be translated
+msgctxt "f_move_data_and_photos_to_main_language"
+msgid "Move all data and selected photos in {language} to the main language of the product: {main_language}"
+msgstr "Move all data and selected photos in {language} to the main language of the product: {main_language}"
msgctxt "move_data_and_photos_to_main_language_replace"
msgid "Replace existing values and selected photos"
@@ -5790,15 +5790,15 @@ msgctxt "carbon_footprint"
msgid "Carbon footprint"
msgstr "Carbon footprint"
-# %s will be replaced by a number
-msgctxt "s_carbon_footprint_per_100g_of_product"
-msgid "%s g CO² per 100g of product"
-msgstr "%s g CO² per 100g of product"
+# variable names between { } must not be translated
+msgctxt "f_carbon_footprint_per_100g_of_product"
+msgid "{grams} g CO² per 100g of product"
+msgstr "{grams} g CO² per 100g of product"
-# %s will be replaced by a number
-msgctxt "equal_to_driving_s_km_in_a_petrol_car"
-msgid "Equal to driving %s km in a petrol car"
-msgstr "Equal to driving %s km in a petrol car"
+# variable names between { } must not be translated
+msgctxt "f_equal_to_driving_km_in_a_petrol_car"
+msgid "Equal to driving {kilometers} km in a petrol car"
+msgstr "Equal to driving {kilometers} km in a petrol car"
msgctxt "source_ademe_agribalyse"
msgid "Source: ADEME Agribalyse Database"
diff --git a/po/common/en.po b/po/common/en.po
index 1af326899970a..5e9c73bce87f6 100644
--- a/po/common/en.po
+++ b/po/common/en.po
@@ -4317,10 +4317,10 @@ msgctxt "some_unknown_ingredients"
msgid "Some ingredients could not be recognized."
msgstr "Some ingredients could not be recognized."
-# keep the 2 %s : they will be replaced by language names.
-msgctxt "move_data_and_photos_to_main_language"
-msgid "Move all data and selected photos in %s to the main language of the product: %s"
-msgstr "Move all data and selected photos in %s to the main language of the product: %s"
+# variable names between { } must not be translated
+msgctxt "f_move_data_and_photos_to_main_language"
+msgid "Move all data and selected photos in {language} to the main language of the product: {main_language}"
+msgstr "Move all data and selected photos in {language} to the main language of the product: {main_language}"
msgctxt "move_data_and_photos_to_main_language_replace"
msgid "Replace existing values and selected photos"
@@ -5807,15 +5807,15 @@ msgctxt "carbon_footprint"
msgid "Carbon footprint"
msgstr "Carbon footprint"
-# %s will be replaced by a number
-msgctxt "s_carbon_footprint_per_100g_of_product"
-msgid "%s g CO² per 100g of product"
-msgstr "%s g CO² per 100g of product"
+# variable names between { } must not be translated
+msgctxt "f_carbon_footprint_per_100g_of_product"
+msgid "{grams} g CO² per 100g of product"
+msgstr "{grams} g CO² per 100g of product"
-# %s will be replaced by a number
-msgctxt "equal_to_driving_s_km_in_a_petrol_car"
-msgid "Equal to driving %s km in a petrol car"
-msgstr "Equal to driving %s km in a petrol car"
+# variable names between { } must not be translated
+msgctxt "f_equal_to_driving_km_in_a_petrol_car"
+msgid "Equal to driving {kilometers} km in a petrol car"
+msgstr "Equal to driving {kilometers} km in a petrol car"
msgctxt "source_ademe_agribalyse"
msgid "Source: ADEME Agribalyse Database"
@@ -5827,4 +5827,4 @@ msgstr "Environment"
msgctxt "health_card_title"
msgid "Nutrition and health"
-msgstr "Nutrition and health"
\ No newline at end of file
+msgstr "Nutrition and health"
diff --git a/templates/api/knowledge-panels/environment/carbon_footprint.tt.json b/templates/api/knowledge-panels/environment/carbon_footprint.tt.json
index 954a761ee0081..1678b72f6ee10 100644
--- a/templates/api/knowledge-panels/environment/carbon_footprint.tt.json
+++ b/templates/api/knowledge-panels/environment/carbon_footprint.tt.json
@@ -17,9 +17,9 @@
[% END %]
"title_element": {
[% SET driving_100g_rounded = driving_100g FILTER format('%.1f'); %]
- "title": "[% lang_sprintf('equal_to_driving_s_km_in_a_petrol_car', driving_100g_rounded) %]",
+ "title": "[% f_lang('f_equal_to_driving_km_in_a_petrol_car', { 'kilometers' => driving_100g_rounded } ) %]",
[% SET co2_100g_rounded = co2_100g * 1000 FILTER format('%.0f'); %]
- "subtitle": "[% lang_sprintf('s_carbon_footprint_per_100g_of_product', co2_100g_rounded) %]",
+ "subtitle": "[% f_lang('f_carbon_footprint_per_100g_of_product', { 'grams' => co2_100g_rounded }) %]",
"icon_url": "[% static_subdomain %]/images/icons/dist/car.svg",
"icon_color_from_evaluation": true,
},