Skip to content

Commit

Permalink
fix: js and json lang quotes escape (#9822)
Browse files Browse the repository at this point in the history
Translations coming from crowdin might contain single quotes or double quotes. So whenever we use lang in a json or javascript string we should escape quotes.

I created edq and esq (Escape Single/Double Quotes) function for that (1st commit) and applied it in a lot of place (2nd commit). This should be the pattern to use from now on. 

fixes: 
- #9820
  • Loading branch information
alexgarel authored Mar 6, 2024
1 parent 784833e commit a3fcac9
Show file tree
Hide file tree
Showing 63 changed files with 305 additions and 294 deletions.
38 changes: 15 additions & 23 deletions lib/ProductOpener/Display.pm
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,10 @@ sub process_template ($template_filename, $template_data_ref, $result_content_re
$template_data_ref->{sep} = separator_before_colon($lc);
$template_data_ref->{lang} = \⟨
$template_data_ref->{f_lang} = \&f_lang;
# escaping quotes for use in javascript or json
# using short names to favour readability
$template_data_ref->{esq} = sub {escape_char(@_, "\'")}; # esq as escape_single_quote_and_newlines
$template_data_ref->{edq} = sub {escape_char(@_, '"')}; # edq as escape_double_quote
$template_data_ref->{lang_sprintf} = \&lang_sprintf;
$template_data_ref->{lc} = $lc;
$template_data_ref->{cc} = $cc;
Expand Down Expand Up @@ -5736,18 +5740,6 @@ sub search_and_export_products ($request_ref, $query_ref, $sort_by) {
return;
}

sub escape_single_quote ($s) {

# some app escape single quotes already, so we have \' already
if (not defined $s) {
return '';
}
$s =~ s/\\'/'/g;
$s =~ s/'/\\'/g;
$s =~ s/\n/ /g;
return $s;
}

@search_series = (qw/organic fairtrade with_sweeteners default/);

my %search_series_colors = (
Expand Down Expand Up @@ -5802,29 +5794,29 @@ sub get_search_field_title_and_details ($field) {

if ($field eq 'additives_n') {
$allow_decimals = "allowDecimals:false,\n";
$title = escape_single_quote(lang("number_of_additives"));
$title = escape_single_quote_and_newlines(lang("number_of_additives"));
}
elsif ($field eq "forest_footprint") {
$allow_decimals = "allowDecimals:true,\n";
$title = escape_single_quote(lang($field));
$title = escape_single_quote_and_newlines(lang($field));
}
elsif ($field =~ /_n$/) {
$allow_decimals = "allowDecimals:false,\n";
$title = escape_single_quote(lang($field . "_s"));
$title = escape_single_quote_and_newlines(lang($field . "_s"));
}
elsif ($field eq "product_quantity") {
$allow_decimals = "allowDecimals:false,\n";
$title = escape_single_quote(lang("quantity"));
$title = escape_single_quote_and_newlines(lang("quantity"));
$unit = ' (g)';
$unit2 = 'g';
}
elsif ($field eq "nova_group") {
$allow_decimals = "allowDecimals:false,\n";
$title = escape_single_quote(lang("nova_groups_s"));
$title = escape_single_quote_and_newlines(lang("nova_groups_s"));
}
elsif ($field eq "ecoscore_score") {
$allow_decimals = "allowDecimals:false,\n";
$title = escape_single_quote(lang("ecoscore_score"));
$title = escape_single_quote_and_newlines(lang("ecoscore_score"));
}
elsif ($field =~ /^packagings_materials\.([^.]+)\.([^.]+)$/) {
my $material = $1;
Expand Down Expand Up @@ -6265,7 +6257,7 @@ sub display_histogram ($graph_ref, $products_ref) {
}

$axis_details{"y"} = {
title => escape_single_quote(lang("number_of_products")),
title => escape_single_quote_and_newlines(lang("number_of_products")),
allow_decimals => "allowDecimals:false,\n",
unit => '',
unit2 => '',
Expand Down Expand Up @@ -6679,7 +6671,7 @@ sub search_and_graph_products ($request_ref, $query_ref, $graph_ref) {

if ($count > 0) {

$graph_ref->{graph_title} = escape_single_quote($graph_ref->{graph_title});
$graph_ref->{graph_title} = escape_single_quote_and_newlines($graph_ref->{graph_title});

# 1 axis: histogram / bar chart -> axis_y == "product_n" or is empty
# 2 axis: scatter plot
Expand Down Expand Up @@ -6810,7 +6802,7 @@ sub map_of_products ($products_iter, $request_ref, $graph_ref) {
init_packager_codes();
init_geocode_addresses();

$graph_ref->{graph_title} = escape_single_quote($graph_ref->{graph_title});
$graph_ref->{graph_title} = escape_single_quote_and_newlines($graph_ref->{graph_title});

my $matching_products = 0;
my $places = 0;
Expand All @@ -6823,7 +6815,7 @@ sub map_of_products ($products_iter, $request_ref, $graph_ref) {
while (my $product_ref = $products_iter->()) {
my $url = $formatted_subdomain . product_url($product_ref->{code});

my $manufacturing_places = escape_single_quote($product_ref->{"manufacturing_places"});
my $manufacturing_places = escape_single_quote_and_newlines($product_ref->{"manufacturing_places"});
$manufacturing_places =~ s/,( )?/, /g;
if ($manufacturing_places ne '') {
$manufacturing_places
Expand All @@ -6832,7 +6824,7 @@ sub map_of_products ($products_iter, $request_ref, $graph_ref) {
. $manufacturing_places . "<br>";
}

my $origins = escape_single_quote($product_ref->{origins});
my $origins = escape_single_quote_and_newlines($product_ref->{origins});
$origins =~ s/,( )?/, /g;
if ($origins ne '') {
$origins = ucfirst(lang("origins_p")) . separator_before_colon($lc) . ": " . $origins . "<br>";
Expand Down
21 changes: 1 addition & 20 deletions lib/ProductOpener/Lang.pm
Original file line number Diff line number Diff line change
Expand Up @@ -119,26 +119,7 @@ In the .po translation files, we use the msgctxt field for the string id.
=cut

sub lang ($stringid) {

my $short_l = undef;
if ($lang =~ /_/) {
$short_l = $`; # pt_pt
}

# English values have been copied to languages that do not have defined values

if (not defined $Lang{$stringid}) {
return '';
}
elsif (defined $Lang{$stringid}{$lang}) {
return $Lang{$stringid}{$lang};
}
elsif ((defined $short_l) and (defined $Lang{$stringid}{$short_l}) and ($Lang{$stringid}{$short_l} ne '')) {
return $Lang{$stringid}{$short_l};
}
else {
return '';
}
return lang_in_other_lc($lang, $stringid);
}

=head2 f_lang( $stringid, $variables_ref )
Expand Down
37 changes: 37 additions & 0 deletions lib/ProductOpener/Text.pm
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ BEGIN {
&get_decimal_formatter
&get_percent_formatter
&escape_char
&escape_single_quote_and_newlines
&remove_tags
&remove_tags_and_quote
Expand Down Expand Up @@ -161,6 +163,41 @@ sub get_decimal_formatter ($locale) {

}

=head2 escape_char( $s, $char )
Escape character $char in string $s
This is use in templates to say escape single quote or double quote
for expressions displayed with single/double quotes (in json or HTML for example)
=cut

sub escape_char($s, $char) {
if ($s && $char) {
# normalize already escaped chars to avoid double escaping
$s =~ s/\\$char/$char/g;
$s =~ s/$char/\\$char/g;
}
return $s;
}

=head2 escape_single_quote_and_newlines( $s )
Escape single quotes in $s but also transform newlines to spaces
=cut

sub escape_single_quote_and_newlines ($s) {

if (not defined $s) {
return '';
}
# some app escape single quotes already, so we have \' already
$s =~ s/\\'/'/g;
$s =~ s/'/\\'/g;
$s =~ s/\n/ /g;
return $s;
}

=head2 get_percent_formatter( LOCALE, MAXIMUM_FRACTION_DIGITS )
C<get_percent_formatter()> formats percentages according to locale. The formatting is locale sensitive.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"contribution"
],
"title_element": {
"title": "[% lang('contribution_panel_title') %]",
"title": "[% edq(lang('contribution_panel_title')) %]",
},
"elements": [
[%# Panels displaying data_quality errors / warnings / info %]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
[% icon_name = "data-info" %]
[% END %]
"title_element": {
"title": "[% lang(panel.tags_type _ '_panel_title') %]",
"subtitle": "[% lang(panel.tags_type _ '_panel_subtitle') %]",
"title": "[% edq(lang(panel.tags_type _ '_panel_title')) %]",
"subtitle": "[% edq(lang(panel.tags_type _ '_panel_subtitle')) %]",
"icon_url": "[% static_subdomain %]/images/icons/dist/[% icon_name %].svg",
"icon_color_from_evaluation": true,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@
[% END %]
"title_element": {
[% SET driving_100g_rounded = sprintf('%.1f', driving_100g) %]
"title": "[% f_lang('f_equal_to_driving_km_in_a_petrol_car', { 'kilometers' => driving_100g_rounded } ) %]",
"title": "[% edq(f_lang('f_equal_to_driving_km_in_a_petrol_car', { 'kilometers' => driving_100g_rounded } )) %]",
[% SET co2_100g_rounded = sprintf('%.0f', co2_100g * 1000) %]
"subtitle": "[% f_lang('f_carbon_footprint_per_100g_of_product', { 'grams' => co2_100g_rounded }) %]",
"subtitle": "[% edq(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,
},
Expand All @@ -40,14 +40,14 @@
"table_element": {
"id": "ecoscore_carbon_impact_by_stages_table",
"table_type": "percents",
"title": "[% lang('ecoscore_impact_detail_by_stages') %]",
"title": "[% edq(lang('ecoscore_impact_detail_by_stages')) %]",
"columns": [
{
"text": "[% lang('ecoscore_stage') %]",
"text": "[% edq(lang('ecoscore_stage')) %]",
"type": "text",
},
{
"text": "[% lang('ecoscore_impact') %]",
"text": "[% edq(lang('ecoscore_impact')) %]",
"type": "percent",
}
],
Expand All @@ -58,7 +58,7 @@
"values": [
{
"icon_url": "[% static_subdomain %]/images/icons/dist/[% step %].svg",
"text": "[% lang("ecoscore_$step") %]"
"text": "[% edq(lang("ecoscore_$step")) %]"
},
{
[% co2_step = "co2_$step" %]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
"icon_url": "[% static_subdomain %]/images/icons/dist/lca.svg",
"icon_color_from_evaluation": true,
"icon_size": "small",
"title": "[% lang('average_impact_of_the_category') %][% sep %]: [% panel.agribalyse_grade FILTER upper %] (Score: [% panel.agribalyse_score %]/100)",
"subtitle": "[% lang('categories_s') FILTER ucfirst %][% sep %]: [% panel.agribalyse_category_name.dquote %]",
"title": "[% edq(lang('average_impact_of_the_category')) %][% sep %]: [% panel.agribalyse_grade FILTER upper %] (Score: [% panel.agribalyse_score %]/100)",
"subtitle": "[% edq(lang('categories_s')) FILTER ucfirst %][% sep %]: [% panel.agribalyse_category_name.dquote %]",
"type": "grade",
"grade": "[% panel.agribalyse_grade %]",
},
Expand Down Expand Up @@ -39,14 +39,14 @@
"table_element": {
"id": "ecoscore_lca_impacts_by_stages_table",
"table_type": "percents",
"title": "[% lang('ecoscore_impact_detail_by_stages') %]",
"title": "[% edq(lang('ecoscore_impact_detail_by_stages')) %]",
"columns": [
{
"text": "[% lang('ecoscore_stage') %]",
"text": "[% edq(lang('ecoscore_stage')) %]",
"type": "text",
},
{
"text": "[% lang('ecoscore_impact') %]",
"text": "[% edq(lang('ecoscore_impact')) %]",
"type": "percent",
}
],
Expand All @@ -57,7 +57,7 @@
"values": [
{
"icon_url": "[% static_subdomain %]/images/icons/dist/[% step %].svg",
"text": "[% lang("ecoscore_$step") %]"
"text": "[% edq(lang("ecoscore_$step")) %]"
},
{
[% ef_step = "ef_$step" %]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
{
"element_type": "panel_group",
"panel_group_element": {
"title": "[% lang('life_cycle_analysis') %]",
"title": "[% edq(lang('life_cycle_analysis')) %]",
"panel_ids": [
"ecoscore_agribalyse",
],
Expand All @@ -50,7 +50,7 @@
{
"element_type": "panel_group",
"panel_group_element": {
"title": "[% lang('ecoscore_bonuses_and_maluses') %]",
"title": "[% edq(lang('ecoscore_bonuses_and_maluses')) %]",
"panel_ids": [
[% FOREACH adjustment IN ["production_system", "origins_of_ingredients", "threatened_species", "packaging"] %]
[% IF (adjustment == "origins_of_ingredients") or (adjustment == "packaging") or (product.ecoscore_data.adjustments.$adjustment.value != 0) %]
Expand All @@ -63,7 +63,7 @@
{
"element_type": "panel_group",
"panel_group_element": {
"title": "[% lang('ecoscore_for_this_product') %]",
"title": "[% edq(lang('ecoscore_for_this_product')) %]",
"panel_ids": [ "ecoscore_total"],
},
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[% SET climate_change_ratio_to_category = panel.climate_change / panel.ecoscore_extended_data_for_category.climate_change %]


// "title": "[% f_lang('f_equal_to_driving_km_in_a_petrol_car', { 'kilometers' => driving_100g_rounded } ) %]",
// "title": "[% edq(f_lang('f_equal_to_driving_km_in_a_petrol_car', { 'kilometers' => driving_100g_rounded } )) %]",
{
"level" :"info",
"topics": [
Expand All @@ -25,7 +25,7 @@
[% SET climate_change_ratio_percent_less = sprintf('%d', (1 - climate_change_ratio_to_category) * 100) %]
"title": "Environmental impact of ingredients [% climate_change_ratio_percent_less %]% smaller than similar products",
[% END %]
"subtitle": "Compared to: [% lang('categories_s') FILTER ucfirst %][% sep %]: [% panel.agribalyse_category_name.dquote %]",
"subtitle": "Compared to: [% edq(lang('categories_s')) FILTER ucfirst %][% sep %]: [% panel.agribalyse_category_name.dquote %]",
"type": "grade",
"icon_url": "[% static_subdomain %]/images/icons/dist/scale-balance.svg",
"icon_color_from_evaluation": true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
],
"title_element": {
"icon_url": "[% static_subdomain %]/images/attributes/dist/ecoscore-not-applicable.svg",
"title": "[% lang("attribute_ecoscore_not_applicable_title") %]",
"title": "[% edq(lang('attribute_ecoscore_not_applicable_title')) %]",
"subtitle": "[% panel.subtitle %]",
"type": "grade",
"grade": "unknown",
Expand All @@ -15,7 +15,7 @@
"element_type": "text",
"text_element": {
"type": "summary",
"html": "[% lang("ecoscore_not_applicable_coming_soon") %]"
"html": "[% edq(lang('ecoscore_not_applicable_coming_soon')) %]"
}
},
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
],
"title_element": {
"icon_url": "[% static_subdomain %]/images/attributes/dist/ecoscore-unknown.svg",
"title": "[% lang("attribute_ecoscore_unknown_title") %] - [% lang("attribute_ecoscore_unknown_description_short") %]",
"title": "[% edq(lang('attribute_ecoscore_unknown_title')) %] - [% edq(lang('attribute_ecoscore_unknown_description_short')) %]",
"type": "grade",
"grade": "unknown",
},
Expand All @@ -14,7 +14,7 @@
"element_type": "text",
"text_element": {
"type": "summary",
"html": "[% lang("ecoscore_unknown_call_to_help") %]"
"html": "[% edq(lang('ecoscore_unknown_call_to_help')) %]"
}
},
{
Expand Down
Loading

0 comments on commit a3fcac9

Please sign in to comment.