diff --git a/.perlcriticrc b/.perlcriticrc
index a2887711ee1de..bd19d17c46618 100644
--- a/.perlcriticrc
+++ b/.perlcriticrc
@@ -49,5 +49,5 @@ equivalent_modules = ProductOpener::PerlStandards
# severity 3
-#[Variables::ProhibitUnusedVariables]
+[Variables::ProhibitUnusedVariables]
# /end severity 3
diff --git a/.perltidy_excludes b/.perltidy_excludes
index de68fd851d822..9a1894df15688 100644
--- a/.perltidy_excludes
+++ b/.perltidy_excludes
@@ -210,9 +210,6 @@ t/additives_tags.t
t/allergens.t
t/allergens_tags.t
t/attributes.t
-t/dataquality.t
-t/dataqualityfood.t
-t/export.t
t/food_groups.t
t/forest_footprint.t
t/i18n.t
@@ -229,7 +226,6 @@ t/ingredients_parsing_todo.t
t/ingredients_percent.t
t/ingredients_processing.t
t/ingredients_tags.t
-t/lang.t
t/load_csv_or_excel_file.t
t/nova.t
t/numbers.t
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 8c6d2951dfc15..119f7168a2bac 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -4,8 +4,9 @@
* If you would like to work on an issue, drop in a comment at the issue. If it is already assigned to someone, but there is no sign of any work being done, please free to drop in a comment so that the issue can be assigned to you if the previous assignee has dropped it entirely.
## Contributing
+[![Contribute with Gitpod](https://img.shields.io/badge/Contribute%20with-Gitpod-908a85?logo=gitpod)](https://gitpod.io/#https://github.com/openfoodfacts/openfoodfacts-server)
-When contributing to this repository, please first discuss the change you wish to make via issue, or the official [slack channel](https://openfoodfacts.slack.com/).
+When contributing to this repository, please first discuss the change you wish to make via issue, or the official [Slack channel](https://openfoodfacts.slack.com/).
Get started running server in development mode, see [Dev environment quick start guide](./docs/introduction/dev-environment-quick-start-guide.md)
@@ -15,11 +16,11 @@ Get started running server in development mode, see [Dev environment quick start
1. Ensure any install or build dependencies are removed before the end of the layer when doing a build.
2. Check that there are no conflicts and your request passes [Travis](https://travis-ci.org) build. Check the log of the pass test if it fails the build.
3. Give the description of the issue that you want to resolve in the pull request message.
- * The format of the commit message to be fixed is
- **fix:[Description of the issue] Fixes #[issue number]**
+ * The format of the commit message to be fixed is
+ **fix:[Description of the issue] Fixes #[issue number]**
Example: **fix: Add toast warning in `MainActivity.java` Fixes #529**
* We are following [conventional commit](https://www.conventionalcommits.org/en/v1.0.0-beta.2/)
- we a [set of standard prefixes](https://github.com/commitizen/conventional-commit-types/blob/master/index.json)
+ with a [set of standard prefixes](https://github.com/commitizen/conventional-commit-types/blob/master/index.json)
(`fix`, `feat`, `doc`, `build`, `test`…),
with the addition of:
* `l10n` for translations
@@ -28,7 +29,7 @@ Get started running server in development mode, see [Dev environment quick start
## Contributions Best Practices
-### Check before commiting
+### Check before committing
You can save you sometime by running some checks locally before committing.
@@ -38,8 +39,8 @@ You can save you sometime by running some checks locally before committing.
* Write clear meaningful git commit messages (Do read [here](https://chris.beams.io/posts/git-commit/)).
* Make sure your PR's description contains GitHub's special keyword references that automatically close the related issue when the PR is merged(For more info click [here](https://github.com/blog/1506-closing-issues-via-pull-requests)).
-* When you make very very minor changes to a PR of yours (like for example fixing a failing Travis build or some small style corrections or minor changes requested by reviewers) make sure you squash your commits afterward so that you don't have an absurd number of commits for a very small fix(Learn how to squash at [here](https://davidwalsh.name/squash-commits-git)).
-* When you're submitting a PR for a UI-related issue, it would be really awesome if you add a screenshot of your change or a link to a deployment where it can be tested out along with your PR. It makes it very easy for the reviewers and you'll also get reviews quicker.
+* When you make very, very minor changes to a PR of yours (like for example fixing a failing Travis build or some small style corrections or minor changes requested by reviewers) make sure you squash your commits afterward so that you don't have an absurd number of commits for a very small fix(Learn how to squash at [here](https://davidwalsh.name/squash-commits-git)).
+* When you're submitting a PR for a UI-related issue, it would be really awesome if you add a screenshot of your change or a link to a deployment where it can be tested out along with your PR. It makes it very easy for the reviewers, and you'll also get reviews quicker.
### Feature Requests and Bug Reports
diff --git a/README.md b/README.md
index f5ef1dc6dee27..e544f4e10dabb 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-
+
# Open Food Facts - Product Opener (Web Server)
@@ -14,7 +14,7 @@
## What is Product Opener?
-**Product Opener** is the server software for **Open Food Facts** and **Open Beauty Facts**. It is released under the AGPL license and is being developed in Perl, HTML and JavaScript as [Free and Open-Source Software](https://en.wikipedia.org/wiki/Free_and_open-source_software).
+**Product Opener** is the server software for **Open Food Facts** and **Open Beauty Facts**. It is released under the AGPL license and is being developed in Perl, HTML and JavaScript as [Free and Open-Source Software](https://en.wikipedia.org/wiki/Free_and_open-source_software).
It works together with [Robotoff](https://github.com/openfoodfacts/robotoff), Open Food Facts' AI system (in Python, which can also be installed locally) and the [Open Food Facts apps](https://github.com/openfoodfacts/smooth-app) (which can work with your local instance after enabling dev mode)
@@ -36,7 +36,7 @@ Data about food is of public interest and has to be open (i.e available to every
*
## Priorities
-* Please list priority issues here
+* Please list priority issues here
* Please add roadmaps here
* [P1 problems](https://github.com/openfoodfacts/openfoodfacts-server/labels/P1)
* [P1 candidates](https://github.com/openfoodfacts/openfoodfacts-server/labels/P1%20candidate)
@@ -49,6 +49,7 @@ Data about food is of public interest and has to be open (i.e available to every
* Developer documentation:
* [Quick start guide (Docker)](./docs/introduction/dev-environment-quick-start-guide.md)
* [Developer guide (Docker)](./docs/how-to-guides/docker-developer-guide.md)
+ * [Developer guide (Gitpod)](./docs/how-to-guides/use-gitpod.md)
* [Manual installation](https://wiki.openfoodfacts.org/Product_Opener/Installation)
* Configuration [TBA]
* Dependencies [TBA]
@@ -60,7 +61,7 @@ Note: documentation follows the [Diátaxis Framework](https://diataxis.fr/)
## Contribution guidelines
-If you're new to Open-Source, we recommend you to Checkout our [_Contributing Guidelines_](https://github.com/openfoodfacts/openfoodfacts-server/blob/master/CONTRIBUTING.md). Feel free to fork the project and send us a pull request.
+If you're new to Open-Source, we recommend you to check out our [_Contributing Guidelines_](https://github.com/openfoodfacts/openfoodfacts-server/blob/master/CONTRIBUTING.md). Feel free to fork the project and send us a pull request.
* Writing tests
* Code review
diff --git a/cgi/minion_job_status.pl b/cgi/minion_job_status.pl
index 69b0ea7bebfbd..a7efd6e15c18a 100755
--- a/cgi/minion_job_status.pl
+++ b/cgi/minion_job_status.pl
@@ -51,8 +51,6 @@
ProductOpener::Display::init();
-my $import_files_ref;
-
my $job_id = param("job_id");
my %data;
diff --git a/cgi/search.pl b/cgi/search.pl
index a730ec1236dc8..082c7ffadb923 100755
--- a/cgi/search.pl
+++ b/cgi/search.pl
@@ -259,7 +259,6 @@
my %search_fields_labels = ();
my @tags_fields_options;
- my @contains;
push(
@tags_fields_options,
diff --git a/docs/how-to-guides/use-gitpod.md b/docs/how-to-guides/use-gitpod.md
new file mode 100644
index 0000000000000..d1c1e1ae0b2d6
--- /dev/null
+++ b/docs/how-to-guides/use-gitpod.md
@@ -0,0 +1,42 @@
+# Using Gitpod for Remote Development
+
+[Gitpod](https://gitpod.io) provides powerful ready-to-code developer environments in the cloud eliminating the friction
+of setting up local environments and IDEs with Perl, Docker and plugins, making it possible for even new contributors to
+OpenFoodFacts Server to get started in minutes instead of hours!
+
+Note that while this how-to is tailored for Gitpod, using alternatives like [GitHub Codespaces][github-codespaces] should be
+similar.
+
+For the most part, development on Gitpod is similar to developing locally as documented
+in the [quickstart guide](../introduction/dev-environment-quick-start-guide.md)
+and [docker-developer-guide](docker-developer-guide.md), however accessing your dev-deployment of
+`openfoodfacts-server` requires an extra step.
+
+## Get Started
+
+[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/https://github.com/openfoodfacts/openfoodfacts-server/)
+> Gitpod will automatically clone and open the repository for you in VSCode by default. It will also automatically build
+> the project for you on opening and comes with Docker and other tools pre-installed making it one of the fastest ways
+> to spin up an environment for `openfoodfacts-server`.
+
+Once the repository is open in Gitpod, other instructions in the
+[quick-start guide](../introduction/dev-environment-quick-start-guide.md) can be generally followed.
+
+## Accessing your development instance of OpenFoodFacts Web
+
+Since Gitpod runs your code in a remote machine, your dev-deployment spun up with `make dev` or `make up` will not
+accessible when you open the default http://openfoodfacts.localhost in your browser. This occurs because the server
+running on the remote machine is not accessible on your local network interface.
+
+To overcome this, we can make use of SSH tunnel that listens to your local port 80 and forwards traffic to the port 80
+of the remote machine. Gitpod makes it really simple to SSH into your dev environment by letting you copy the `ssh`
+command required to reach your remote environment. To start, follow the ssh instructions on Gitpod's official
+guide: [SSH for workspaces as easy as copy/paste][gitpod-ssh-guide]. Once you have copied the ssh command and ensure it
+works as-is, add a `-L 80:localhost:80` to the command to make it look like:
+`ssh -L 80:localhost:80 'openfoodfac-openfoodfac-tok-openfoodfac-r9f61214h9vt.ssh.ws-c.gitpod.io'`.
+
+Once you execute the altered command in your terminal, you should be able to access OpenFoodFacts
+on http://openfoodfacts.localhost just as documented in the quickstart guide!
+
+[gitpod-ssh-guide]: https://www.gitpod.io/blog/copy-paste-ssh-workspace-access
+[github-codespaces]: https://github.com/features/codespaces
diff --git a/docs/introduction/dev-environment-quick-start-guide.md b/docs/introduction/dev-environment-quick-start-guide.md
index 118c416dd231a..e3a24e63e44ae 100644
--- a/docs/introduction/dev-environment-quick-start-guide.md
+++ b/docs/introduction/dev-environment-quick-start-guide.md
@@ -1,6 +1,8 @@
# Dev environment quick start guide
This guide will allow you to rapidly build a ready-to-use development environment for **Product Opener** running in Docker.
+As an alternative to setting up your environment locally, follow the [Gitpod how-to guide](../how-to-guides/use-gitpod.md)
+to instantly provision a ready-to-code development environment in the cloud.
First setup time estimate is `~10min` with the following specs:
* `8 GB` of RAM dedicated to Docker client
@@ -106,7 +108,7 @@ make dev
```
> **Note:**
->
+>
> If docker complains about
> ```
> ERROR: could not find an available, non-overlapping IPv4 address pool among the defaults to assign to the network
diff --git a/lib/ProductOpener/Display.pm b/lib/ProductOpener/Display.pm
index f47a661ae4b18..d3a6838762be3 100644
--- a/lib/ProductOpener/Display.pm
+++ b/lib/ProductOpener/Display.pm
@@ -88,7 +88,8 @@ BEGIN
&get_world_subdomain
- &data_to_display_nutriscore_and_nutrient_levels
+ &data_to_display_nutriscore
+ &data_to_display_nutrient_levels
&data_to_display_ingredients_analysis
&data_to_display_ingredients_analysis_details
@@ -5208,8 +5209,6 @@ sub search_and_display_products($request_ref, $query_ref, $sort_by, $limit, $pag
for my $product_ref (@{$request_ref->{structured_response}{products}}) {
my $img_url;
- my $img_w;
- my $img_h;
my $code = $product_ref->{code};
my $img = display_image_thumb($product_ref, 'front');
@@ -6695,7 +6694,6 @@ sub display_page($request_ref) {
$log->debug("displaying page", { title => $title }) if $log->is_debug();
- my $object_ref;
my $type;
my $id;
@@ -6908,7 +6906,6 @@ sub display_page($request_ref) {
my $image_banner = "";
my $link = lang("donate_link");
my $image;
- my $utm;
my @banners = qw(independent personal research);
my $banner = $banners[time() % @banners];
$image = "/images/banners/donate/donate-banner.$banner.$lc.800x150.svg";
@@ -7858,15 +7855,16 @@ HTML
# Display Nutri-Score and nutrient levels
- my $template_data_nutriscore_and_nutrient_levels_ref = data_to_display_nutriscore_and_nutrient_levels($product_ref);
+ my $template_data_nutriscore_ref = data_to_display_nutriscore($product_ref);
+ my $template_data_nutrient_levels_ref = data_to_display_nutrient_levels($product_ref);
my $nutriscore_html = '';
my $nutrient_levels_html = '';
- if (not $template_data_nutriscore_and_nutrient_levels_ref->{do_not_display}) {
+ if (not $template_data_nutrient_levels_ref->{do_not_display}) {
- process_template('web/pages/product/includes/nutriscore.tt.html', $template_data_nutriscore_and_nutrient_levels_ref, \$nutriscore_html) || return "template error: " . $tt->error();
- process_template('web/pages/product/includes/nutrient_levels.tt.html', $template_data_nutriscore_and_nutrient_levels_ref, \$nutrient_levels_html) || return "template error: " . $tt->error();
+ process_template('web/pages/product/includes/nutriscore.tt.html', $template_data_nutriscore_ref, \$nutriscore_html) || return "template error: " . $tt->error();
+ process_template('web/pages/product/includes/nutrient_levels.tt.html', $template_data_nutrient_levels_ref, \$nutrient_levels_html) || return "template error: " . $tt->error();
}
$template_data_ref->{display_nutriscore} = $nutriscore_html;
@@ -8611,9 +8609,9 @@ sub display_nutriscore_calculation_details($nutriscore_data_ref) {
}
-=head2 data_to_display_nutriscore_and_nutrient_levels ( $product_ref )
+=head2 data_to_display_nutrient_levels ( $product_ref )
-Generates a data structure to display the Nutri-Score and the nutrient levels (food trafic lights).
+Generates a data structure to display the nutrient levels (food trafic lights).
The resulting data structure can be passed to a template to generate HTML or the JSON data for a knowledge panel.
@@ -8627,11 +8625,81 @@ Reference to a data structure with needed data to display.
=cut
-sub data_to_display_nutriscore_and_nutrient_levels($product_ref) {
+sub data_to_display_nutrient_levels($product_ref) {
my $result_data_ref = {};
- # Populate the data templates needed to display the Nutri-Score and nutrient levels
+ # Do not display traffic lights for baby foods
+ if (has_tag($product_ref, "categories", "en:baby-foods")) {
+
+ $result_data_ref->{do_not_display} = 1;
+ }
+
+ # do not compute a score for dehydrated products to be rehydrated (e.g. dried soups, coffee, tea)
+ # unless we have nutrition data for the prepared product
+
+ my $prepared = "";
+
+ foreach my $category_tag ("en:dried-products-to-be-rehydrated", "en:chocolate-powders", "en:dessert-mixes", "en:flavoured-syrups") {
+
+ if (has_tag($product_ref, "categories", $category_tag)) {
+
+ if ((defined $product_ref->{nutriments}{"energy_prepared_100g"})) {
+ $prepared = '_prepared';
+ last;
+ }
+ else {
+ $result_data_ref->{do_not_display} = 1;
+ }
+ }
+ }
+
+ if (not $result_data_ref->{do_not_display}) {
+
+ $result_data_ref->{nutrient_levels} = [];
+
+ foreach my $nutrient_level_ref (@nutrient_levels) {
+ my ($nid, $low, $high) = @{$nutrient_level_ref};
+
+ if ((defined $product_ref->{nutrient_levels}) and (defined $product_ref->{nutrient_levels}{$nid})) {
+
+ push @{$result_data_ref->{nutrient_levels}}, {
+ nid => $nid,
+ nutrient_level => $product_ref->{nutrient_levels}{$nid},
+ nutrient_quantity_in_grams => sprintf("%.2e", $product_ref->{nutriments}{$nid . $prepared . "_100g"}) + 0.0,
+ nutrient_in_quantity => sprintf(lang("nutrient_in_quantity"), display_taxonomy_tag($lc, "nutrients", "zz:$nid") , lang($product_ref->{nutrient_levels}{$nid} . "_quantity")),
+ # Needed for the current display on product page, can be removed once transitioned fully to knowledge panels
+ nutrient_bold_in_quantity => sprintf(lang("nutrient_in_quantity"), "" . display_taxonomy_tag($lc, "nutrients", "zz:$nid") . "", lang($product_ref->{nutrient_levels}{$nid} . "_quantity")),
+ };
+ }
+ }
+ }
+
+ return $result_data_ref;
+}
+
+
+=head2 data_to_display_nutriscore ( $product_ref )
+
+Generates a data structure to display the Nutri-Score.
+
+The resulting data structure can be passed to a template to generate HTML or the JSON data for a knowledge panel.
+
+=head3 Arguments
+
+=head4 Product reference $product_ref
+
+=head3 Return values
+
+Reference to a data structure with needed data to display.
+
+=cut
+
+sub data_to_display_nutriscore($) {
+
+ my $product_ref = shift;
+
+ my $result_data_ref = {};
# Nutri-Score data
@@ -8735,60 +8803,14 @@ sub data_to_display_nutriscore_and_nutrient_levels($product_ref) {
$result_data_ref->{nutriscore_details} = display_nutriscore_calculation_details($product_ref->{nutriscore_data});
}
-
- # Nutrient levels data
-
- # Do not display traffic lights for baby foods
- if (has_tag($product_ref, "categories", "en:baby-foods")) {
-
- $result_data_ref->{do_not_display} = 1;
- }
-
- # do not compute a score for dehydrated products to be rehydrated (e.g. dried soups, coffee, tea)
- # unless we have nutrition data for the prepared product
-
- my $prepared = "";
-
- foreach my $category_tag ("en:dried-products-to-be-rehydrated", "en:chocolate-powders", "en:dessert-mixes", "en:flavoured-syrups") {
-
- if (has_tag($product_ref, "categories", $category_tag)) {
-
- if ((defined $product_ref->{nutriments}{"energy_prepared_100g"})) {
- $prepared = '_prepared';
- last;
- }
- else {
- $result_data_ref->{do_not_display} = 1;
- }
- }
- }
-
- if (not $result_data_ref->{do_not_display}) {
-
- $result_data_ref->{nutrient_levels} = [];
-
- foreach my $nutrient_level_ref (@nutrient_levels) {
- my ($nid, $low, $high) = @{$nutrient_level_ref};
-
- if ((defined $product_ref->{nutrient_levels}) and (defined $product_ref->{nutrient_levels}{$nid})) {
-
- push @{$result_data_ref->{nutrient_levels}}, {
- nutrient_level => $product_ref->{nutrient_levels}{$nid},
- nutriment_prepared => sprintf("%.2e", $product_ref->{nutriments}{$nid . $prepared . "_100g"}) + 0.0,
- nutriment_quantity => sprintf(lang("nutrient_in_quantity"), "" . display_taxonomy_tag($lc, "nutrients", "zz:$nid") . "", lang($product_ref->{nutrient_levels}{$nid} . "_quantity")),
- };
- }
- }
- }
-
-
return $result_data_ref;
}
sub add_product_nutriment_to_stats($nutriments_ref, $nid, $value) {
- if ($value ne '') {
+
+ if ((defined $value) and ($value ne '')) {
if (not defined $nutriments_ref->{"${nid}_n"}) {
$nutriments_ref->{"${nid}_n"} = 0;
@@ -9270,7 +9292,6 @@ CSS
}
my @columns;
my @extra_row_columns;
- my @ecological_impact_columns;
my $extra_row = 0; # Some rows will trigger an extra row (e.g. Salt adds Sodium)
diff --git a/lib/ProductOpener/ForestFootprint.pm b/lib/ProductOpener/ForestFootprint.pm
index 2492ee1cef2f6..de0c6ac6375e5 100644
--- a/lib/ProductOpener/ForestFootprint.pm
+++ b/lib/ProductOpener/ForestFootprint.pm
@@ -440,8 +440,6 @@ sub compute_footprints_of_ingredients($$$) {
foreach my $ingredient_ref (@$ingredients_ref) {
- my $ingredient_origins_ref;
-
# If we are at the first level of the ingredients array,
# ingredients have a rank, except the sub-ingredients listed at the end
if ($ingredient_ref->{rank}) {
diff --git a/lib/ProductOpener/Ingredients.pm b/lib/ProductOpener/Ingredients.pm
index ce470b21b87e8..d1b882cd1ba03 100644
--- a/lib/ProductOpener/Ingredients.pm
+++ b/lib/ProductOpener/Ingredients.pm
@@ -5243,7 +5243,6 @@ sub extract_ingredients_classes_from_text($) {
}
}
- my $with_sweeteners;
my %all_seen = (); # used to not tag "huile végétale" if we have seen "huile de palme" already
diff --git a/lib/ProductOpener/KnowledgePanels.pm b/lib/ProductOpener/KnowledgePanels.pm
index 335dc9d8ce93d..6980c6c4164b3 100644
--- a/lib/ProductOpener/KnowledgePanels.pm
+++ b/lib/ProductOpener/KnowledgePanels.pm
@@ -761,6 +761,8 @@ sub create_health_card_panel($$$$) {
create_nutriscore_panel($product_ref, $target_lc, $target_cc);
+ create_nutrient_levels_panels($product_ref, $target_lc, $target_cc);
+
create_nutrition_facts_table_panel($product_ref, $target_lc, $target_cc);
if ($options_ref->{activate_knowledge_panel_physical_activities}) {
@@ -809,7 +811,9 @@ sub create_nutriscore_panel($$$) {
$log->debug("create nutriscore panel", { code => $product_ref->{code}, nutriscore_data => $product_ref->{nutriscore_data} }) if $log->is_debug();
- my $panel_data_ref = data_to_display_nutriscore_and_nutrient_levels($product_ref);
+ my $panel_data_ref = data_to_display_nutriscore($product_ref);
+
+ # Nutri-Score panel
if ($panel_data_ref->{nutriscore_grade} eq "not-applicable") {
$panel_data_ref->{title} = lang_in_other_lc($target_lc, "attribute_nutriscore_not_applicable_title");
@@ -824,6 +828,46 @@ sub create_nutriscore_panel($$$) {
}
+=head2 create_nutrient_levels_panels ( $product_ref, $target_lc, $target_cc )
+
+Creates knowledge panels for nutrient levels for fat, saturated fat, sugars and salt.
+
+=head3 Arguments
+
+=head4 product reference $product_ref
+
+Loaded from the MongoDB database, Storable files, or the OFF API.
+
+=head4 language code $target_lc
+
+Returned attributes contain both data and strings intended to be displayed to users.
+This parameter sets the desired language for the user facing strings.
+
+=head4 country code $target_cc
+
+=cut
+
+sub create_nutrient_levels_panels($$$) {
+
+ my $product_ref = shift;
+ my $target_lc = shift;
+ my $target_cc = shift;
+
+ $log->debug("create nutriscore panel", { code => $product_ref->{code}, nutriscore_data => $product_ref->{nutriscore_data} }) if $log->is_debug();
+
+ my $nutrient_levels_ref = data_to_display_nutrient_levels($product_ref);
+
+ # Nutrient levels panels
+ if (not $nutrient_levels_ref->{do_not_display}) {
+ foreach my $nutrient_level_ref (@{$nutrient_levels_ref->{nutrient_levels}}) {
+ my $nid = $nutrient_level_ref->{nid};
+ create_panel_from_json_template("nutrient_level_" . $nid, "api/knowledge-panels/health/nutrition/nutrient_level.tt.json",
+ $nutrient_level_ref, $product_ref, $target_lc, $target_cc);
+ }
+ }
+}
+
+
=head2 create_nutrition_facts_table_panel ( $product_ref, $target_lc, $target_cc )
Creates a knowledge panel with the nutrition facts table.
diff --git a/lib/ProductOpener/Tags.pm b/lib/ProductOpener/Tags.pm
index 6d4af78707b25..091b1ae5a66a5 100644
--- a/lib/ProductOpener/Tags.pm
+++ b/lib/ProductOpener/Tags.pm
@@ -2512,7 +2512,6 @@ sub get_taxonomy_tag_and_link_for_lang($$$) {
my $tagid = shift;
my $tag_lc;
- my $tag_url;
if ($tagid =~ /^(\w\w):/) {
$tag_lc = $1;
diff --git a/po/common/common.pot b/po/common/common.pot
index 757c91dfe015f..1c16e453a5dde 100644
--- a/po/common/common.pot
+++ b/po/common/common.pot
@@ -6196,4 +6196,63 @@ msgctxt "action_add_nutrition_facts"
msgid "Add nutrition facts"
msgstr "Add nutrition facts"
-
+# Used as a header for key facts
+msgctxt "knowledge_panels_facts"
+msgid "What you need to know"
+msgstr "What you need to know"
+
+msgctxt "knowledge_panels_recommendation"
+msgid "Recommendation"
+msgstr "Recommendation"
+
+msgctxt "nutrient_info_salt_risk"
+msgid "A high consumption of salt (or sodium) can cause raised blood pressure, which can increase the risk of heart disease and stroke."
+msgstr "A high consumption of salt (or sodium) can cause raised blood pressure, which can increase the risk of heart disease and stroke."
+
+msgctxt "nutrient_info_salt_high_blood_pressure"
+msgid "Many people who have high blood pressure do not know it, as there are often no symptoms."
+msgstr "Many people who have high blood pressure do not know it, as there are often no symptoms."
+
+msgctxt "nutrient_info_salt_high_consumption"
+msgid "Most people consume too much salt (on average 9 to 12 grams per day), around twice the recommended maximum level of intake."
+msgstr "Most people consume too much salt (on average 9 to 12 grams per day), around twice the recommended maximum level of intake."
+
+msgctxt "nutrient_recommendation_salt_title"
+msgid "Limit the consumption of salt and salted food"
+msgstr "Limit the consumption of salt and salted food"
+
+msgctxt "nutrient_recommendation_salt_cooking_and_table"
+msgid "Reduce the quantity of salt used when cooking, and don't salt again at the table."
+msgstr "Reduce the quantity of salt used when cooking, and don't salt again at the table."
+
+msgctxt "nutrient_recommendation_salt_limit_salty_snacks"
+msgid "Limit the consumption of salty snacks and choose products with lower salt content."
+msgstr "Limit the consumption of salty snacks and choose products with lower salt content."
+
+msgctxt "nutrient_info_sugars_risk"
+msgid "A high consumption of sugar can cause weight gain and tooth decay. It also augments the risk of type 2 diabetes and cardio-vascular diseases."
+msgstr "A high consumption of sugar can cause weight gain and tooth decay. It also augments the risk of type 2 diabetes and cardio-vascular diseases."
+
+msgctxt "nutrient_recommendation_sugars_title"
+msgid "Limit the consumption of sugar and sugary drinks"
+msgstr "Limit the consumption of sugar and sugary drinks"
+
+msgctxt "nutrient_recommendation_sugars_drinks"
+msgid "Sugary drinks (such as sodas, fruit beverages, and fruit juices and nectars) should be limited as much as possible (no more than 1 glass a day)."
+msgstr "Sugary drinks (such as sodas, fruit beverages, and fruit juices and nectars) should be limited as much as possible (no more than 1 glass a day)."
+
+msgctxt "nutrient_recommendation_sugars_food"
+msgid "Choose products with lower sugar content and reduce the consumption of products with added sugars."
+msgstr "Choose products with lower sugar content and reduce the consumption of products with added sugars."
+
+msgctxt "nutrient_info_fat_and_saturated_fat_risk"
+msgid "A high consumption of fat, especially saturated fats, can raise cholesterol, which increases the risk of heart diseases."
+msgstr "A high consumption of fat, especially saturated fats, can raise cholesterol, which increases the risk of heart diseases."
+
+msgctxt "nutrient_recommendation_fat_and_saturated_fat_title"
+msgid "Reduce the consumption of fat and saturated fat"
+msgstr "Limit the consumption of fat and saturated fat"
+
+msgctxt "nutrient_recommendation_fat_and_saturated_fat"
+msgid "Choose products with lower fat and saturated fat content."
+msgstr "Choose products with lower fat and saturated fat content."
diff --git a/po/common/en.po b/po/common/en.po
index db0dc7220df2a..35054c7e3ca4a 100644
--- a/po/common/en.po
+++ b/po/common/en.po
@@ -6218,3 +6218,66 @@ msgctxt "action_add_nutrition_facts"
msgid "Add nutrition facts"
msgstr "Add nutrition facts"
+# Used as a header for key facts
+msgctxt "knowledge_panels_facts"
+msgid "What you need to know"
+msgstr "What you need to know"
+
+msgctxt "knowledge_panels_recommendation"
+msgid "Recommendation"
+msgstr "Recommendation"
+
+msgctxt "nutrient_info_salt_risk"
+msgid "A high consumption of salt (or sodium) can cause raised blood pressure, which can increase the risk of heart disease and stroke."
+msgstr "A high consumption of salt (or sodium) can cause raised blood pressure, which can increase the risk of heart disease and stroke."
+
+msgctxt "nutrient_info_salt_high_blood_pressure"
+msgid "Many people who have high blood pressure do not know it, as there are often no symptoms."
+msgstr "Many people who have high blood pressure do not know it, as there are often no symptoms."
+
+msgctxt "nutrient_info_salt_high_consumption"
+msgid "Most people consume too much salt (on average 9 to 12 grams per day), around twice the recommended maximum level of intake."
+msgstr "Most people consume too much salt (on average 9 to 12 grams per day), around twice the recommended maximum level of intake."
+
+msgctxt "nutrient_recommendation_salt_title"
+msgid "Limit the consumption of salt and salted food"
+msgstr "Limit the consumption of salt and salted food"
+
+msgctxt "nutrient_recommendation_salt_cooking_and_table"
+msgid "Reduce the quantity of salt used when cooking, and don't salt again at the table."
+msgstr "Reduce the quantity of salt used when cooking, and don't salt again at the table."
+
+msgctxt "nutrient_recommendation_salt_limit_salty_snacks"
+msgid "Limit the consumption of salty snacks and choose products with lower salt content."
+msgstr "Limit the consumption of salty snacks and choose products with lower salt content."
+
+msgctxt "nutrient_info_sugars_risk"
+msgid "A high consumption of sugar can cause weight gain and tooth decay. It also augments the risk of type 2 diabetes and cardio-vascular diseases."
+msgstr "A high consumption of sugar can cause weight gain and tooth decay. It also augments the risk of type 2 diabetes and cardio-vascular diseases."
+
+msgctxt "nutrient_recommendation_sugars_title"
+msgid "Limit the consumption of sugar and sugary drinks"
+msgstr "Limit the consumption of sugar and sugary drinks"
+
+msgctxt "nutrient_recommendation_sugars_drinks"
+msgid "Sugary drinks (such as sodas, fruit beverages, and fruit juices and nectars) should be limited as much as possible (no more than 1 glass a day)."
+msgstr "Sugary drinks (such as sodas, fruit beverages, and fruit juices and nectars) should be limited as much as possible (no more than 1 glass a day)."
+
+msgctxt "nutrient_recommendation_sugars_food"
+msgid "Choose products with lower sugar content and reduce the consumption of products with added sugars."
+msgstr "Choose products with lower sugar content and reduce the consumption of products with added sugars."
+
+msgctxt "nutrient_info_fat_and_saturated_fat_risk"
+msgid "A high consumption of fat, especially saturated fats, can raise cholesterol, which increases the risk of heart diseases."
+msgstr "A high consumption of fat, especially saturated fats, can raise cholesterol, which increases the risk of heart diseases."
+
+msgctxt "nutrient_recommendation_fat_and_saturated_fat_title"
+msgid "Reduce the consumption of fat and saturated fat"
+msgstr "Limit the consumption of fat and saturated fat"
+
+msgctxt "nutrient_recommendation_fat_and_saturated_fat"
+msgid "Choose products with lower fat and saturated fat content."
+msgstr "Choose products with lower fat and saturated fat content."
+
+
+
diff --git a/scripts/obsolete/import_openfood_ch_name_translations.pl b/scripts/obsolete/import_openfood_ch_name_translations.pl
index 36d9fb367268a..4af4a7cccbd7f 100755
--- a/scripts/obsolete/import_openfood_ch_name_translations.pl
+++ b/scripts/obsolete/import_openfood_ch_name_translations.pl
@@ -1271,7 +1271,6 @@
#print $json;
my @modified_fields;
- my @images_ids;
my $openfood_ref = decode_json($json);
my $openfood_id = $openfood_ref->{data}{id};
diff --git a/scripts/run_cloud_vision_ocr.pl b/scripts/run_cloud_vision_ocr.pl
index dbb10e3030045..2f57eec22c13c 100755
--- a/scripts/run_cloud_vision_ocr.pl
+++ b/scripts/run_cloud_vision_ocr.pl
@@ -114,8 +114,6 @@
my $cloud_vision_response = $ua->request($request);
-my $status;
-
if ($cloud_vision_response->is_success) {
$log->info("request to google cloud vision was successful") if $log->is_info();
diff --git a/scripts/tag_stores_magasins_u.pl b/scripts/tag_stores_magasins_u.pl
index 333fff692d8a9..f2e3cfbb6611a 100755
--- a/scripts/tag_stores_magasins_u.pl
+++ b/scripts/tag_stores_magasins_u.pl
@@ -130,7 +130,6 @@
my $modified = 0;
my @modified_fields;
- my @images_ids;
my $code = $imported_product_ref->{"EAN PRINCIPAL"};
diff --git a/t/dataquality.t b/t/dataquality.t
index a5706dbcea390..1a308b780d774 100644
--- a/t/dataquality.t
+++ b/t/dataquality.t
@@ -14,11 +14,11 @@ sub check_quality_and_test_product_has_quality_tag($$$$) {
my $reason = shift;
my $yesno = shift;
ProductOpener::DataQuality::check_quality($product_ref);
- if ($yesno){
- ok( has_tag($product_ref, 'data_quality', $tag), $reason ) or diag explain $product_ref;
+ if ($yesno) {
+ ok(has_tag($product_ref, 'data_quality', $tag), $reason) or diag explain $product_ref;
}
else {
- ok( !has_tag($product_ref, 'data_quality', $tag), $reason ) or diag explain $product_ref;
+ ok(!has_tag($product_ref, 'data_quality', $tag), $reason) or diag explain $product_ref;
}
return;
@@ -30,66 +30,133 @@ sub product_with_code_has_quality_tag($$$$) {
my $reason = shift;
my $yesno = shift;
- my $product_ref = {
- code => $code
- };
+ my $product_ref = {code => $code};
check_quality_and_test_product_has_quality_tag($product_ref, $tag, $reason, $yesno);
return;
}
-
# gs1-issn-prefix
-product_with_code_has_quality_tag('977000000000', 'en:gs1-issn-prefix', 'product with GTIN-12 has gs1-issn-prefix tag because of the barcode prefix 977', 1);
-product_with_code_has_quality_tag('9770000000000', 'en:gs1-issn-prefix', 'product with GTIN-13 has gs1-issn-prefix tag because of the barcode prefix 977', 1);
-product_with_code_has_quality_tag('976000000000', 'en:gs1-issn-prefix', 'product with GTIN-12 has no gs1-issn-prefix tag because of the barcode prefix 976', 0);
-product_with_code_has_quality_tag('9760000000000', 'en:gs1-issn-prefix', 'product with GTIN-13 has no gs1-issn-prefix tag because of the barcode prefix 976', 0);
+product_with_code_has_quality_tag('977000000000', 'en:gs1-issn-prefix',
+ 'product with GTIN-12 has gs1-issn-prefix tag because of the barcode prefix 977', 1);
+product_with_code_has_quality_tag('9770000000000', 'en:gs1-issn-prefix',
+ 'product with GTIN-13 has gs1-issn-prefix tag because of the barcode prefix 977', 1);
+product_with_code_has_quality_tag('976000000000', 'en:gs1-issn-prefix',
+ 'product with GTIN-12 has no gs1-issn-prefix tag because of the barcode prefix 976', 0);
+product_with_code_has_quality_tag('9760000000000', 'en:gs1-issn-prefix',
+ 'product with GTIN-13 has no gs1-issn-prefix tag because of the barcode prefix 976', 0);
# gs1-isbn-prefix
-product_with_code_has_quality_tag('978000000000', 'en:gs1-isbn-prefix', 'product with GTIN-12 has gs1-isbn-prefix tag because of the barcode prefix 978', 1);
-product_with_code_has_quality_tag('9780000000000', 'en:gs1-isbn-prefix', 'product with GTIN-13 has gs1-isbn-prefix tag because of the barcode prefix 978', 1);
-product_with_code_has_quality_tag('979000000000', 'en:gs1-isbn-prefix', 'product with GTIN-12 has gs1-isbn-prefix tag because of the barcode prefix 979', 1);
-product_with_code_has_quality_tag('9790000000000', 'en:gs1-isbn-prefix', 'product with GTIN-13 has gs1-isbn-prefix tag because of the barcode prefix 979', 1);
-product_with_code_has_quality_tag('976000000000', 'en:gs1-isbn-prefix', 'product with GTIN-12 has no gs1-isbn-prefix tag because of the barcode prefix 976', 0);
-product_with_code_has_quality_tag('9760000000000', 'en:gs1-isbn-prefix', 'product with GTIN-13 has no gs1-isbn-prefix tag because of the barcode prefix 976', 0);
+product_with_code_has_quality_tag('978000000000', 'en:gs1-isbn-prefix',
+ 'product with GTIN-12 has gs1-isbn-prefix tag because of the barcode prefix 978', 1);
+product_with_code_has_quality_tag('9780000000000', 'en:gs1-isbn-prefix',
+ 'product with GTIN-13 has gs1-isbn-prefix tag because of the barcode prefix 978', 1);
+product_with_code_has_quality_tag('979000000000', 'en:gs1-isbn-prefix',
+ 'product with GTIN-12 has gs1-isbn-prefix tag because of the barcode prefix 979', 1);
+product_with_code_has_quality_tag('9790000000000', 'en:gs1-isbn-prefix',
+ 'product with GTIN-13 has gs1-isbn-prefix tag because of the barcode prefix 979', 1);
+product_with_code_has_quality_tag('976000000000', 'en:gs1-isbn-prefix',
+ 'product with GTIN-12 has no gs1-isbn-prefix tag because of the barcode prefix 976', 0);
+product_with_code_has_quality_tag('9760000000000', 'en:gs1-isbn-prefix',
+ 'product with GTIN-13 has no gs1-isbn-prefix tag because of the barcode prefix 976', 0);
# gs1-refund-prefix
-product_with_code_has_quality_tag('980000000000', 'en:gs1-refund-prefix', 'product with GTIN-12 has gs1-refund-prefix tag because of the barcode prefix 980', 1);
-product_with_code_has_quality_tag('9800000000000', 'en:gs1-refund-prefix', 'product with GTIN-13 has gs1-refund-prefix tag because of the barcode prefix 980', 1);
-product_with_code_has_quality_tag('976000000000', 'en:gs1-refund-prefix', 'product with GTIN-12 has no gs1-refund-prefix tag because of the barcode prefix 976', 0);
-product_with_code_has_quality_tag('9760000000000', 'en:gs1-refund-prefix', 'product with GTIN-13 has no gs1-refund-prefix tag because of the barcode prefix 976', 0);
+product_with_code_has_quality_tag('980000000000', 'en:gs1-refund-prefix',
+ 'product with GTIN-12 has gs1-refund-prefix tag because of the barcode prefix 980', 1);
+product_with_code_has_quality_tag('9800000000000', 'en:gs1-refund-prefix',
+ 'product with GTIN-13 has gs1-refund-prefix tag because of the barcode prefix 980', 1);
+product_with_code_has_quality_tag('976000000000', 'en:gs1-refund-prefix',
+ 'product with GTIN-12 has no gs1-refund-prefix tag because of the barcode prefix 976', 0);
+product_with_code_has_quality_tag('9760000000000', 'en:gs1-refund-prefix',
+ 'product with GTIN-13 has no gs1-refund-prefix tag because of the barcode prefix 976', 0);
# gs1-coupon-common-currency-area-prefix
-product_with_code_has_quality_tag('981000000000', 'en:gs1-coupon-common-currency-area-prefix', 'product with GTIN-12 has gs1-coupon-common-currency-area-prefix tag because of the barcode prefix 981', 1);
-product_with_code_has_quality_tag('9810000000000', 'en:gs1-coupon-common-currency-area-prefix', 'product with GTIN-13 has gs1-coupon-common-currency-area-prefix tag because of the barcode prefix 981', 1);
-product_with_code_has_quality_tag('982000000000', 'en:gs1-coupon-common-currency-area-prefix', 'product with GTIN-12 has gs1-coupon-common-currency-area-prefix tag because of the barcode prefix 982', 1);
-product_with_code_has_quality_tag('9820000000000', 'en:gs1-coupon-common-currency-area-prefix', 'product with GTIN-13 has gs1-coupon-common-currency-area-prefix tag because of the barcode prefix 982', 1);
-product_with_code_has_quality_tag('983000000000', 'en:gs1-coupon-common-currency-area-prefix', 'product with GTIN-12 has gs1-coupon-common-currency-area-prefix tag because of the barcode prefix 983', 1);
-product_with_code_has_quality_tag('9830000000000', 'en:gs1-coupon-common-currency-area-prefix', 'product with GTIN-13 has gs1-coupon-common-currency-area-prefix tag because of the barcode prefix 983', 1);
-product_with_code_has_quality_tag('984000000000', 'en:gs1-coupon-common-currency-area-prefix', 'product with GTIN-12 has gs1-coupon-common-currency-area-prefix tag because of the barcode prefix 984', 1);
-product_with_code_has_quality_tag('9840000000000', 'en:gs1-coupon-common-currency-area-prefix', 'product with GTIN-13 has gs1-coupon-common-currency-area-prefix tag because of the barcode prefix 984', 1);
-product_with_code_has_quality_tag('976000000000', 'en:gs1-coupon-common-currency-area-prefix', 'product with GTIN-12 has no gs1-coupon-common-currency-area-prefix tag because of the barcode prefix 976', 0);
-product_with_code_has_quality_tag('9760000000000', 'en:gs1-coupon-common-currency-area-prefix', 'product with GTIN-13 has no gs1-coupon-common-currency-area-prefix tag because of the barcode prefix 976', 0);
+product_with_code_has_quality_tag(
+ '981000000000',
+ 'en:gs1-coupon-common-currency-area-prefix',
+ 'product with GTIN-12 has gs1-coupon-common-currency-area-prefix tag because of the barcode prefix 981', 1
+);
+product_with_code_has_quality_tag(
+ '9810000000000',
+ 'en:gs1-coupon-common-currency-area-prefix',
+ 'product with GTIN-13 has gs1-coupon-common-currency-area-prefix tag because of the barcode prefix 981', 1
+);
+product_with_code_has_quality_tag(
+ '982000000000',
+ 'en:gs1-coupon-common-currency-area-prefix',
+ 'product with GTIN-12 has gs1-coupon-common-currency-area-prefix tag because of the barcode prefix 982', 1
+);
+product_with_code_has_quality_tag(
+ '9820000000000',
+ 'en:gs1-coupon-common-currency-area-prefix',
+ 'product with GTIN-13 has gs1-coupon-common-currency-area-prefix tag because of the barcode prefix 982', 1
+);
+product_with_code_has_quality_tag(
+ '983000000000',
+ 'en:gs1-coupon-common-currency-area-prefix',
+ 'product with GTIN-12 has gs1-coupon-common-currency-area-prefix tag because of the barcode prefix 983', 1
+);
+product_with_code_has_quality_tag(
+ '9830000000000',
+ 'en:gs1-coupon-common-currency-area-prefix',
+ 'product with GTIN-13 has gs1-coupon-common-currency-area-prefix tag because of the barcode prefix 983', 1
+);
+product_with_code_has_quality_tag(
+ '984000000000',
+ 'en:gs1-coupon-common-currency-area-prefix',
+ 'product with GTIN-12 has gs1-coupon-common-currency-area-prefix tag because of the barcode prefix 984', 1
+);
+product_with_code_has_quality_tag(
+ '9840000000000',
+ 'en:gs1-coupon-common-currency-area-prefix',
+ 'product with GTIN-13 has gs1-coupon-common-currency-area-prefix tag because of the barcode prefix 984', 1
+);
+product_with_code_has_quality_tag(
+ '976000000000',
+ 'en:gs1-coupon-common-currency-area-prefix',
+ 'product with GTIN-12 has no gs1-coupon-common-currency-area-prefix tag because of the barcode prefix 976', 0
+);
+product_with_code_has_quality_tag(
+ '9760000000000',
+ 'en:gs1-coupon-common-currency-area-prefix',
+ 'product with GTIN-13 has no gs1-coupon-common-currency-area-prefix tag because of the barcode prefix 976', 0
+);
# gs1-future-coupon-prefix
-product_with_code_has_quality_tag('985000000000', 'en:gs1-future-coupon-prefix', 'product with GTIN-12 has gs1-future-coupon-prefix tag because of the barcode prefix 985', 1);
-product_with_code_has_quality_tag('9850000000000', 'en:gs1-future-coupon-prefix', 'product with GTIN-13 has gs1-future-coupon-prefix tag because of the barcode prefix 985', 1);
-product_with_code_has_quality_tag('986000000000', 'en:gs1-future-coupon-prefix', 'product with GTIN-12 has gs1-future-coupon-prefix tag because of the barcode prefix 986', 1);
-product_with_code_has_quality_tag('9860000000000', 'en:gs1-future-coupon-prefix', 'product with GTIN-13 has gs1-future-coupon-prefix tag because of the barcode prefix 986', 1);
-product_with_code_has_quality_tag('987000000000', 'en:gs1-future-coupon-prefix', 'product with GTIN-12 has gs1-future-coupon-prefix tag because of the barcode prefix 987', 1);
-product_with_code_has_quality_tag('9870000000000', 'en:gs1-future-coupon-prefix', 'product with GTIN-13 has gs1-future-coupon-prefix tag because of the barcode prefix 987', 1);
-product_with_code_has_quality_tag('988000000000', 'en:gs1-future-coupon-prefix', 'product with GTIN-12 has gs1-future-coupon-prefix tag because of the barcode prefix 988', 1);
-product_with_code_has_quality_tag('9880000000000', 'en:gs1-future-coupon-prefix', 'product with GTIN-13 has gs1-future-coupon-prefix tag because of the barcode prefix 988', 1);
-product_with_code_has_quality_tag('989000000000', 'en:gs1-future-coupon-prefix', 'product with GTIN-12 has gs1-future-coupon-prefix tag because of the barcode prefix 989', 1);
-product_with_code_has_quality_tag('9890000000000', 'en:gs1-future-coupon-prefix', 'product with GTIN-13 has gs1-future-coupon-prefix tag because of the barcode prefix 989', 1);
-product_with_code_has_quality_tag('976000000000', 'en:gs1-future-coupon-prefix', 'product with GTIN-12 has no gs1-future-coupon-prefix tag because of the barcode prefix 976', 0);
-product_with_code_has_quality_tag('9760000000000', 'en:gs1-future-coupon-prefix', 'product with GTIN-13 has no gs1-future-coupon-prefix tag because of the barcode prefix 976', 0);
+product_with_code_has_quality_tag('985000000000', 'en:gs1-future-coupon-prefix',
+ 'product with GTIN-12 has gs1-future-coupon-prefix tag because of the barcode prefix 985', 1);
+product_with_code_has_quality_tag('9850000000000', 'en:gs1-future-coupon-prefix',
+ 'product with GTIN-13 has gs1-future-coupon-prefix tag because of the barcode prefix 985', 1);
+product_with_code_has_quality_tag('986000000000', 'en:gs1-future-coupon-prefix',
+ 'product with GTIN-12 has gs1-future-coupon-prefix tag because of the barcode prefix 986', 1);
+product_with_code_has_quality_tag('9860000000000', 'en:gs1-future-coupon-prefix',
+ 'product with GTIN-13 has gs1-future-coupon-prefix tag because of the barcode prefix 986', 1);
+product_with_code_has_quality_tag('987000000000', 'en:gs1-future-coupon-prefix',
+ 'product with GTIN-12 has gs1-future-coupon-prefix tag because of the barcode prefix 987', 1);
+product_with_code_has_quality_tag('9870000000000', 'en:gs1-future-coupon-prefix',
+ 'product with GTIN-13 has gs1-future-coupon-prefix tag because of the barcode prefix 987', 1);
+product_with_code_has_quality_tag('988000000000', 'en:gs1-future-coupon-prefix',
+ 'product with GTIN-12 has gs1-future-coupon-prefix tag because of the barcode prefix 988', 1);
+product_with_code_has_quality_tag('9880000000000', 'en:gs1-future-coupon-prefix',
+ 'product with GTIN-13 has gs1-future-coupon-prefix tag because of the barcode prefix 988', 1);
+product_with_code_has_quality_tag('989000000000', 'en:gs1-future-coupon-prefix',
+ 'product with GTIN-12 has gs1-future-coupon-prefix tag because of the barcode prefix 989', 1);
+product_with_code_has_quality_tag('9890000000000', 'en:gs1-future-coupon-prefix',
+ 'product with GTIN-13 has gs1-future-coupon-prefix tag because of the barcode prefix 989', 1);
+product_with_code_has_quality_tag('976000000000', 'en:gs1-future-coupon-prefix',
+ 'product with GTIN-12 has no gs1-future-coupon-prefix tag because of the barcode prefix 976', 0);
+product_with_code_has_quality_tag('9760000000000', 'en:gs1-future-coupon-prefix',
+ 'product with GTIN-13 has no gs1-future-coupon-prefix tag because of the barcode prefix 976', 0);
# gs1-coupon-prefix
-product_with_code_has_quality_tag('990000000000', 'en:gs1-coupon-prefix', 'product with GTIN-12 has gs1-coupon-prefix tag because of the barcode prefix 99', 1);
-product_with_code_has_quality_tag('9900000000000', 'en:gs1-coupon-prefix', 'product with GTIN-13 has gs1-coupon-prefix tag because of the barcode prefix 99', 1);
-product_with_code_has_quality_tag('976000000000', 'en:gs1-coupon-prefix', 'product with GTIN-12 has no gs1-coupon-prefix tag because of the barcode prefix 976', 0);
-product_with_code_has_quality_tag('9760000000000', 'en:gs1-coupon-prefix', 'product with GTIN-13 has no gs1-coupon-prefix tag because of the barcode prefix 976', 0);
+product_with_code_has_quality_tag('990000000000', 'en:gs1-coupon-prefix',
+ 'product with GTIN-12 has gs1-coupon-prefix tag because of the barcode prefix 99', 1);
+product_with_code_has_quality_tag('9900000000000', 'en:gs1-coupon-prefix',
+ 'product with GTIN-13 has gs1-coupon-prefix tag because of the barcode prefix 99', 1);
+product_with_code_has_quality_tag('976000000000', 'en:gs1-coupon-prefix',
+ 'product with GTIN-12 has no gs1-coupon-prefix tag because of the barcode prefix 976', 0);
+product_with_code_has_quality_tag('9760000000000', 'en:gs1-coupon-prefix',
+ 'product with GTIN-13 has no gs1-coupon-prefix tag because of the barcode prefix 976', 0);
done_testing();
diff --git a/t/dataqualityfood.t b/t/dataqualityfood.t
index c72c4654774b7..cf481537fd684 100644
--- a/t/dataqualityfood.t
+++ b/t/dataqualityfood.t
@@ -15,11 +15,11 @@ sub check_quality_and_test_product_has_quality_tag($$$$) {
my $reason = shift;
my $yesno = shift;
ProductOpener::DataQuality::check_quality($product_ref);
- if ($yesno){
- ok( has_tag($product_ref, 'data_quality', $tag), $reason ) or diag explain $product_ref;
+ if ($yesno) {
+ ok(has_tag($product_ref, 'data_quality', $tag), $reason) or diag explain $product_ref;
}
else {
- ok( !has_tag($product_ref, 'data_quality', $tag), $reason ) or diag explain $product_ref;
+ ok(!has_tag($product_ref, 'data_quality', $tag), $reason) or diag explain $product_ref;
}
return;
@@ -37,36 +37,46 @@ sub product_with_energy_has_quality_tag($$$) {
}
};
- check_quality_and_test_product_has_quality_tag($product_ref, 'en:nutrition-value-over-3800-energy', $reason, $yesno);
+ check_quality_and_test_product_has_quality_tag($product_ref, 'en:nutrition-value-over-3800-energy', $reason,
+ $yesno);
return;
}
# en:nutrition-value-over-3800-energy - does not add tag, if there is no nutriments.
-my $product_ref_without_nutriments = {
- lc => "de"
-};
-check_quality_and_test_product_has_quality_tag($product_ref_without_nutriments, 'en:nutrition-value-over-3800-energy', 'product does not have en:nutrition-value-over-3800-energy tag as it has no nutrients', 0);
+my $product_ref_without_nutriments = {lc => "de"};
+check_quality_and_test_product_has_quality_tag(
+ $product_ref_without_nutriments,
+ 'en:nutrition-value-over-3800-energy',
+ 'product does not have en:nutrition-value-over-3800-energy tag as it has no nutrients', 0
+);
# en:nutrition-value-over-3800-energy - does not add tag, if there is no energy.
my $product_ref_without_energy_value = {
lc => "de",
nutriments => {}
};
-check_quality_and_test_product_has_quality_tag($product_ref_without_energy_value, 'en:nutrition-value-over-3800-energy', 'product does not have en:nutrition-value-over-3800-energy tag as it has no energy_value', 0);
+check_quality_and_test_product_has_quality_tag(
+ $product_ref_without_energy_value,
+ 'en:nutrition-value-over-3800-energy',
+ 'product does not have en:nutrition-value-over-3800-energy tag as it has no energy_value', 0
+);
# en:nutrition-value-over-3800-energy - does not add tag, if energy_value is below 3800 - 3799
-product_with_energy_has_quality_tag(3799, 'product does not have en:nutrition-value-over-3800-energy tag as it has an energy_value below 3800: 3799', 0);
+product_with_energy_has_quality_tag(3799,
+ 'product does not have en:nutrition-value-over-3800-energy tag as it has an energy_value below 3800: 3799', 0);
# en:nutrition-value-over-3800-energy - does not add tag, if energy_value is below 3800 - 40
-product_with_energy_has_quality_tag(40, 'product does not have en:nutrition-value-over-3800-energy tag as it has an energy_value below 3800: 40', 0);
+product_with_energy_has_quality_tag(40,
+ 'product does not have en:nutrition-value-over-3800-energy tag as it has an energy_value below 3800: 40', 0);
# en:nutrition-value-over-3800-energy - does not add tag, if energy_value is equal 3800
-product_with_energy_has_quality_tag(3800, 'product does not have en:nutrition-value-over-3800-energy tag as it has an energy_value of 3800: 3800', 0);
+product_with_energy_has_quality_tag(3800,
+ 'product does not have en:nutrition-value-over-3800-energy tag as it has an energy_value of 3800: 3800', 0);
# en:nutrition-value-over-3800-energy - does add tag, if energy_value is above 3800
-product_with_energy_has_quality_tag(3801, 'product does have en:nutrition-value-over-3800-energy tag as it has an energy_value of 3800: 3801', 1);
-
+product_with_energy_has_quality_tag(3801,
+ 'product does have en:nutrition-value-over-3800-energy tag as it has an energy_value of 3800: 3801', 1);
# ingredients-de-over-30-percent-digits - with more than 30%
my $over_30 = '(52,3 0) 0,2 (J 23 (J 2,3 g 0,15 g';
@@ -79,7 +89,10 @@ my $product_ref = {
ingredients_text_de => $over_30
};
ProductOpener::DataQuality::check_quality($product_ref);
-ok( has_tag($product_ref, 'data_quality', 'en:ingredients-de-over-30-percent-digits'), 'product with more than 30% digits in the language-specific ingredients has tag ingredients-over-30-percent-digits' ) or diag explain $product_ref;
+ok(
+ has_tag($product_ref, 'data_quality', 'en:ingredients-de-over-30-percent-digits'),
+ 'product with more than 30% digits in the language-specific ingredients has tag ingredients-over-30-percent-digits'
+) or diag explain $product_ref;
# ingredients-de-over-30-percent-digits - with exactly 30%
$product_ref = {
@@ -90,7 +103,10 @@ $product_ref = {
ingredients_text_de => $at_30
};
ProductOpener::DataQuality::check_quality($product_ref);
-ok( !has_tag($product_ref, 'data_quality', 'en:ingredients-de-over-30-percent-digits'), 'product with at most 30% digits in the language-specific ingredients has no ingredients-over-30-percent-digits tag' ) or diag explain $product_ref;
+ok(
+ !has_tag($product_ref, 'data_quality', 'en:ingredients-de-over-30-percent-digits'),
+ 'product with at most 30% digits in the language-specific ingredients has no ingredients-over-30-percent-digits tag'
+) or diag explain $product_ref;
# ingredients-de-over-30-percent-digits - without a text
$product_ref = {
@@ -100,7 +116,10 @@ $product_ref = {
}
};
ProductOpener::DataQuality::check_quality($product_ref);
-ok( !has_tag($product_ref, 'data_quality', 'en:ingredients-de-over-30-percent-digits'), 'product with no language-specific ingredients text has no ingredients-over-30-percent-digits tag' ) or diag explain $product_ref;
+ok(
+ !has_tag($product_ref, 'data_quality', 'en:ingredients-de-over-30-percent-digits'),
+ 'product with no language-specific ingredients text has no ingredients-over-30-percent-digits tag'
+) or diag explain $product_ref;
# ingredients-over-30-percent-digits - with more than 30%
$product_ref = {
@@ -108,7 +127,10 @@ $product_ref = {
ingredients_text => $over_30
};
ProductOpener::DataQuality::check_quality($product_ref);
-ok( has_tag($product_ref, 'data_quality', 'en:ingredients-over-30-percent-digits'), 'product with more than 30% digits in the ingredients has tag ingredients-over-30-percent-digits' ) or diag explain $product_ref;
+ok(
+ has_tag($product_ref, 'data_quality', 'en:ingredients-over-30-percent-digits'),
+ 'product with more than 30% digits in the ingredients has tag ingredients-over-30-percent-digits'
+) or diag explain $product_ref;
# ingredients-over-30-percent-digits - with exactly 30%
$product_ref = {
@@ -116,30 +138,40 @@ $product_ref = {
ingredients_text => $at_30
};
ProductOpener::DataQuality::check_quality($product_ref);
-ok( !has_tag($product_ref, 'data_quality', 'en:ingredients-over-30-percent-digits'), 'product with at most 30% digits in the ingredients has no ingredients-over-30-percent-digits tag' ) or diag explain $product_ref;
+ok(
+ !has_tag($product_ref, 'data_quality', 'en:ingredients-over-30-percent-digits'),
+ 'product with at most 30% digits in the ingredients has no ingredients-over-30-percent-digits tag'
+) or diag explain $product_ref;
# ingredients-over-30-percent-digits - without a text
-$product_ref = {
- lc => 'de'
-};
+$product_ref = {lc => 'de'};
ProductOpener::DataQuality::check_quality($product_ref);
-ok( !has_tag($product_ref, 'data_quality', 'en:ingredients-over-30-percent-digits'), 'product with no ingredients text has no ingredients-over-30-percent-digits tag' ) or diag explain $product_ref;
+ok(
+ !has_tag($product_ref, 'data_quality', 'en:ingredients-over-30-percent-digits'),
+ 'product with no ingredients text has no ingredients-over-30-percent-digits tag'
+) or diag explain $product_ref;
# issue 1466: Add quality facet for dehydrated products that are missing prepared values
-$product_ref = {
- categories_tags => undef
-};
+$product_ref = {categories_tags => undef};
ProductOpener::DataQuality::check_quality($product_ref);
-ok( ! has_tag($product_ref, 'data_quality', 'en:missing-nutrition-data-prepared-with-category-dried-products-to-be-rehydrated'),
-'product without dried category with no other qualities is not flagged for issue 1466' ) or diag explain $product_ref;
-
-$product_ref = {
- categories_tags => ['en:dried-products-to-be-rehydrated']
-};
+ok(
+ !has_tag(
+ $product_ref, 'data_quality',
+ 'en:missing-nutrition-data-prepared-with-category-dried-products-to-be-rehydrated'
+ ),
+ 'product without dried category with no other qualities is not flagged for issue 1466'
+) or diag explain $product_ref;
+
+$product_ref = {categories_tags => ['en:dried-products-to-be-rehydrated']};
ProductOpener::DataQuality::check_quality($product_ref);
-ok( has_tag($product_ref, 'data_quality', 'en:missing-nutrition-data-prepared-with-category-dried-products-to-be-rehydrated'),
-'dried product category with no other qualities is flagged for issue 1466' ) or diag explain $product_ref;
+ok(
+ has_tag(
+ $product_ref, 'data_quality',
+ 'en:missing-nutrition-data-prepared-with-category-dried-products-to-be-rehydrated'
+ ),
+ 'dried product category with no other qualities is flagged for issue 1466'
+) or diag explain $product_ref;
# positive control 1
$product_ref = {
@@ -150,8 +182,13 @@ $product_ref = {
}
};
ProductOpener::DataQuality::check_quality($product_ref);
-ok( ! has_tag($product_ref, 'data_quality', 'en:missing-nutrition-data-prepared-with-category-dried-products-to-be-rehydrated'),
-'dried product category with prepared data is not flagged for issue 1466' ) or diag explain $product_ref;
+ok(
+ !has_tag(
+ $product_ref, 'data_quality',
+ 'en:missing-nutrition-data-prepared-with-category-dried-products-to-be-rehydrated'
+ ),
+ 'dried product category with prepared data is not flagged for issue 1466'
+) or diag explain $product_ref;
# positive control 2
$product_ref = {
@@ -163,8 +200,13 @@ $product_ref = {
}
};
ProductOpener::DataQuality::check_quality($product_ref);
-ok( ! has_tag($product_ref, 'data_quality', 'en:missing-nutrition-data-prepared-with-category-dried-products-to-be-rehydrated'),
-'dried product category with 2 prepared data values is not flagged for issue 1466' ) or diag explain $product_ref;
+ok(
+ !has_tag(
+ $product_ref, 'data_quality',
+ 'en:missing-nutrition-data-prepared-with-category-dried-products-to-be-rehydrated'
+ ),
+ 'dried product category with 2 prepared data values is not flagged for issue 1466'
+) or diag explain $product_ref;
$product_ref = {
categories_tags => ['en:dried-products-to-be-rehydrated'],
@@ -172,8 +214,13 @@ $product_ref = {
nutriments => undef
};
ProductOpener::DataQuality::check_quality($product_ref);
-ok( has_tag($product_ref, 'data_quality', 'en:missing-nutrition-data-prepared-with-category-dried-products-to-be-rehydrated'),
-'dried product category with undefined nutriments hash is flagged for issue 1466' ) or diag explain $product_ref;
+ok(
+ has_tag(
+ $product_ref, 'data_quality',
+ 'en:missing-nutrition-data-prepared-with-category-dried-products-to-be-rehydrated'
+ ),
+ 'dried product category with undefined nutriments hash is flagged for issue 1466'
+) or diag explain $product_ref;
$product_ref = {
categories_tags => ['en:dried-products-to-be-rehydrated'],
@@ -183,8 +230,13 @@ $product_ref = {
}
};
ProductOpener::DataQuality::check_quality($product_ref);
-ok( has_tag($product_ref, 'data_quality', 'en:missing-nutrition-data-prepared-with-category-dried-products-to-be-rehydrated'),
-'dried product category with nutriments hash with unrelated data is flagged for issue 1466' ) or diag explain $product_ref;
+ok(
+ has_tag(
+ $product_ref, 'data_quality',
+ 'en:missing-nutrition-data-prepared-with-category-dried-products-to-be-rehydrated'
+ ),
+ 'dried product category with nutriments hash with unrelated data is flagged for issue 1466'
+) or diag explain $product_ref;
$product_ref = {
categories_tags => ['en:dried-products-to-be-rehydrated'],
@@ -193,8 +245,13 @@ $product_ref = {
}
};
ProductOpener::DataQuality::check_quality($product_ref);
-ok( has_tag($product_ref, 'data_quality', 'en:missing-nutrition-data-prepared-with-category-dried-products-to-be-rehydrated'),
-'dried product category with nutrition_data_prepared off is flagged for issue 1466' ) or diag explain $product_ref;
+ok(
+ has_tag(
+ $product_ref, 'data_quality',
+ 'en:missing-nutrition-data-prepared-with-category-dried-products-to-be-rehydrated'
+ ),
+ 'dried product category with nutrition_data_prepared off is flagged for issue 1466'
+) or diag explain $product_ref;
$product_ref = {
categories_tags => ['en:dried-products-to-be-rehydrated'],
@@ -206,9 +263,13 @@ $product_ref = {
};
ProductOpener::DataQuality::check_quality($product_ref);
-ok( has_tag($product_ref, 'data_quality', 'en:missing-nutrition-data-prepared-with-category-dried-products-to-be-rehydrated'),
-'dried product category with no nutrition data checked prepared data is flagged for issue 1466' ) or diag explain $product_ref;
-
+ok(
+ has_tag(
+ $product_ref, 'data_quality',
+ 'en:missing-nutrition-data-prepared-with-category-dried-products-to-be-rehydrated'
+ ),
+ 'dried product category with no nutrition data checked prepared data is flagged for issue 1466'
+) or diag explain $product_ref;
$product_ref = {
categories_tags => ['en:dried-products-to-be-rehydrated'],
@@ -220,35 +281,42 @@ $product_ref = {
};
ProductOpener::DataQuality::check_quality($product_ref);
-ok( has_tag($product_ref, 'data_quality', 'en:missing-nutrition-data-prepared-with-category-dried-products-to-be-rehydrated'),
-'dried product category with no nutrition data checked prepared data is flagged for issue 1466' ) or diag explain $product_ref;
+ok(
+ has_tag(
+ $product_ref, 'data_quality',
+ 'en:missing-nutrition-data-prepared-with-category-dried-products-to-be-rehydrated'
+ ),
+ 'dried product category with no nutrition data checked prepared data is flagged for issue 1466'
+) or diag explain $product_ref;
use Log::Any::Adapter 'TAP', filter => "none";
-check_quality_and_test_product_has_quality_tag({
- 'ecoscore_data' => {
- 'adjustments' => {
- 'origins_of_ingredients' => {
- 'aggregated_origins' => [
- {
- 'origin' => 'en:unknown',
- 'percent' => 100
- }
- ],
- 'epi_score' => 0,
- 'epi_value' => -5,
- 'origins_from_origins_field' => [
- 'en:unknown'
- ],
- 'transportation_score' => 0,
- 'transportation_value' => 0,
- 'value' => -5,
- 'warning' => 'origins_are_100_percent_unknown'
- },
- }
- }
-}, "en:ecoscore-origins-of-ingredients-origins-are-100-percent-unknown", "origins 100 percent unknown", 1);
-
+check_quality_and_test_product_has_quality_tag(
+ {
+ 'ecoscore_data' => {
+ 'adjustments' => {
+ 'origins_of_ingredients' => {
+ 'aggregated_origins' => [
+ {
+ 'origin' => 'en:unknown',
+ 'percent' => 100
+ }
+ ],
+ 'epi_score' => 0,
+ 'epi_value' => -5,
+ 'origins_from_origins_field' => ['en:unknown'],
+ 'transportation_score' => 0,
+ 'transportation_value' => 0,
+ 'value' => -5,
+ 'warning' => 'origins_are_100_percent_unknown'
+ },
+ }
+ }
+ },
+ "en:ecoscore-origins-of-ingredients-origins-are-100-percent-unknown",
+ "origins 100 percent unknown",
+ 1
+);
# Specified percent of ingredients
@@ -258,8 +326,9 @@ $product_ref = {
};
extract_ingredients_from_text($product_ref);
ProductOpener::DataQuality::check_quality($product_ref);
-ok( has_tag($product_ref, 'data_quality', 'en:all-ingredients-with-specified-percent')) or diag explain $product_ref;
-ok( has_tag($product_ref, 'data_quality', 'en:sum-of-ingredients-with-unspecified-percent-lesser-than-10')) or diag explain $product_ref;
+ok(has_tag($product_ref, 'data_quality', 'en:all-ingredients-with-specified-percent')) or diag explain $product_ref;
+ok(has_tag($product_ref, 'data_quality', 'en:sum-of-ingredients-with-unspecified-percent-lesser-than-10'))
+ or diag explain $product_ref;
$product_ref = {
lc => 'en',
@@ -267,8 +336,11 @@ $product_ref = {
};
extract_ingredients_from_text($product_ref);
ProductOpener::DataQuality::check_quality($product_ref);
-ok( has_tag($product_ref, 'data_quality', 'en:all-but-one-ingredient-with-specified-percent')) or diag explain $product_ref;
-ok( has_tag($product_ref, 'data_quality', 'en:sum-of-ingredients-with-unspecified-percent-lesser-than-10')) or diag explain $product_ref;
-ok( has_tag($product_ref, 'data_quality', 'en:sum-of-ingredients-with-specified-percent-greater-than-100')) or diag explain $product_ref;
+ok(has_tag($product_ref, 'data_quality', 'en:all-but-one-ingredient-with-specified-percent'))
+ or diag explain $product_ref;
+ok(has_tag($product_ref, 'data_quality', 'en:sum-of-ingredients-with-unspecified-percent-lesser-than-10'))
+ or diag explain $product_ref;
+ok(has_tag($product_ref, 'data_quality', 'en:sum-of-ingredients-with-specified-percent-greater-than-100'))
+ or diag explain $product_ref;
done_testing();
diff --git a/t/export.t b/t/export.t
index 3dca5322f4af2..511560bec3227 100644
--- a/t/export.t
+++ b/t/export.t
@@ -26,7 +26,6 @@ use File::Basename "dirname";
use Getopt::Long;
use JSON;
-
my $test_id = "export";
my $test_dir = dirname(__FILE__);
@@ -40,13 +39,13 @@ actual test results can be saved by passing --update-expected-results
The directory will be created if it does not already exist.
TXT
-;
+ ;
my $update_expected_results;
-GetOptions ("update-expected-results" => \$update_expected_results)
+GetOptions("update-expected-results" => \$update_expected_results)
or die("Error in command line arguments.\n\n" . $usage);
-
+
# Remove all products
ProductOpener::Test::remove_all_products();
@@ -70,7 +69,7 @@ my $import_args_ref = {
no_source => 1,
};
-my $stats_ref = import_csv_file( $import_args_ref );
+my $stats_ref = import_csv_file($import_args_ref);
# Export products
@@ -80,20 +79,22 @@ my $separator = "\t";
# CSV export
my $exported_csv_file = "/tmp/export.csv";
-open (my $exported_csv, ">:encoding(UTF-8)", $exported_csv_file) or die("Could not create $exported_csv_file: $!\n");
+open(my $exported_csv, ">:encoding(UTF-8)", $exported_csv_file) or die("Could not create $exported_csv_file: $!\n");
-my $export_args_ref = {filehandle=>$exported_csv, separator=>$separator, query=>$query_ref, cc => "fr" };
+my $export_args_ref = {filehandle => $exported_csv, separator => $separator, query => $query_ref, cc => "fr"};
export_csv($export_args_ref);
close($exported_csv);
-ProductOpener::Test::compare_csv_file_to_expected_results($exported_csv_file, $test_dir . "/expected_test_results/export", $update_expected_results);
+ProductOpener::Test::compare_csv_file_to_expected_results($exported_csv_file,
+ $test_dir . "/expected_test_results/export",
+ $update_expected_results);
# Export more fields
$exported_csv_file = "/tmp/export_more_fields.csv";
-open ($exported_csv, ">:encoding(UTF-8)", $exported_csv_file) or die("Could not create $exported_csv_file: $!\n");
+open($exported_csv, ">:encoding(UTF-8)", $exported_csv_file) or die("Could not create $exported_csv_file: $!\n");
$export_args_ref->{filehandle} = $exported_csv;
$export_args_ref->{export_computed_fields} = 1;
@@ -103,7 +104,8 @@ export_csv($export_args_ref);
close($exported_csv);
-ProductOpener::Test::compare_csv_file_to_expected_results($exported_csv_file, $test_dir . "/expected_test_results/export_more_fields", $update_expected_results);
-
+ProductOpener::Test::compare_csv_file_to_expected_results($exported_csv_file,
+ $test_dir . "/expected_test_results/export_more_fields",
+ $update_expected_results);
done_testing();
diff --git a/t/food.t b/t/food.t
index df1fe518b0165..86669cc2429bd 100644
--- a/t/food.t
+++ b/t/food.t
@@ -486,7 +486,6 @@ $product_ref = {};
my $value = "50.1";
my $modifier;
-my $unit;
# test we have no modifier
normalize_nutriment_value_and_modifier(\$value, \$modifier);
is($value, "50.1");
@@ -610,6 +609,7 @@ assign_nid_modifier_value_and_unit($product_ref, "vitamin-a", undef, 40, "IU");
assign_nid_modifier_value_and_unit($product_ref, "vitamin-e", undef, 40, "IU");
assign_nid_modifier_value_and_unit($product_ref, "calcium", undef, 20, "% DV");
assign_nid_modifier_value_and_unit($product_ref, "vitamin-d", undef, 20, "% DV");
+assign_nid_modifier_value_and_unit($product_ref, "vitamin-b1", undef, 100, "% DV");
is_deeply($product_ref,
{
@@ -620,6 +620,9 @@ is_deeply($product_ref,
'vitamin-a' => '1.2e-05',
'vitamin-a_unit' => 'IU',
'vitamin-a_value' => 40,
+ 'vitamin-b1' => '0.0012',
+ 'vitamin-b1_unit' => '% DV',
+ 'vitamin-b1_value' => 100,
'vitamin-d' => '8e-06',
'vitamin-d_unit' => '% DV',
'vitamin-d_value' => 20,
diff --git a/t/ingredients_percent.t b/t/ingredients_percent.t
index cd21ee3439dce..e749d6819af50 100755
--- a/t/ingredients_percent.t
+++ b/t/ingredients_percent.t
@@ -668,7 +668,7 @@ my @tests = (
'text' => 'water'
},
{
- 'id' => 'en:fruit-concentrates',
+ 'id' => 'en:fruit-concentrate',
'ingredients' => [
{
'id' => 'en:apple',
@@ -715,7 +715,7 @@ my @tests = (
'text' => 'water'
},
{
- 'id' => 'en:fruit-concentrates',
+ 'id' => 'en:fruit-concentrate',
'ingredients' => [
{
'id' => 'en:apple',
diff --git a/t/lang.t b/t/lang.t
index 10b07e275800a..2f322c2876548 100644
--- a/t/lang.t
+++ b/t/lang.t
@@ -24,13 +24,16 @@ sub test_links {
}
# https://stackoverflow.com/a/190405/11963
-my $abs_regex = qr/^[a-z](?:[-a-z0-9\+\.])*:(?:\/\/(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&'\(\)\*\+,;=:])*@)?(?:\[(?:(?:(?:[0-9a-f]{1,4}:){6}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|::(?:[0-9a-f]{1,4}:){5}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:[0-9a-f]{1,4}:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|v[0-9a-f]+[-a-z0-9\._~!\$&'\(\)\*\+,;=:]+)\]|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}|(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&'\(\)\*\+,;=@])*)(?::[0-9]*)?(?:\/(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&'\(\)\*\+,;=:@]))*)*|\/(?:(?:(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&'\(\)\*\+,;=:@]))+)(?:\/(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&'\(\)\*\+,;=:@]))*)*)?|(?:(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&'\(\)\*\+,;=:@]))+)(?:\/(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&'\(\)\*\+,;=:@]))*)*|(?!(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&'\(\)\*\+,;=:@])))(?:\?(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&'\(\)\*\+,;=:@])|[\x{E000}-\x{F8FF}\x{F0000}-\x{FFFFD}\x{100000}-\x{10FFFD}\/\?])*)?(?:\#(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&'\(\)\*\+,;=:@])|[\/\?])*)?$/i;
-my @full_links = qw(android_apk_app_link android_app_link donate_link footer_blog_link footer_wiki_link ios_app_link windows_phone_app_link donate_link);
+my $abs_regex
+ = qr/^[a-z](?:[-a-z0-9\+\.])*:(?:\/\/(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&'\(\)\*\+,;=:])*@)?(?:\[(?:(?:(?:[0-9a-f]{1,4}:){6}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|::(?:[0-9a-f]{1,4}:){5}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:[0-9a-f]{1,4}:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|v[0-9a-f]+[-a-z0-9\._~!\$&'\(\)\*\+,;=:]+)\]|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}|(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&'\(\)\*\+,;=@])*)(?::[0-9]*)?(?:\/(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&'\(\)\*\+,;=:@]))*)*|\/(?:(?:(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&'\(\)\*\+,;=:@]))+)(?:\/(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&'\(\)\*\+,;=:@]))*)*)?|(?:(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&'\(\)\*\+,;=:@]))+)(?:\/(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&'\(\)\*\+,;=:@]))*)*|(?!(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&'\(\)\*\+,;=:@])))(?:\?(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&'\(\)\*\+,;=:@])|[\x{E000}-\x{F8FF}\x{F0000}-\x{FFFFD}\x{100000}-\x{10FFFD}\/\?])*)?(?:\#(?:(?:%[0-9a-f][0-9a-f]|[-a-z0-9\._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!\$&'\(\)\*\+,;=:@])|[\/\?])*)?$/i;
+my @full_links
+ = qw(android_apk_app_link android_app_link donate_link footer_blog_link footer_wiki_link ios_app_link windows_phone_app_link donate_link);
test_links($abs_regex, @full_links);
# https://www.regexpal.com/96861
my $slug_regex = qr/^\/[a-z0-9]+(?:-[a-z0-9]+)*$/i;
-my @slug_links = qw(footer_code_of_conduct_link footer_data_link footer_faq_link footer_legal_link footer_press_link footer_terms_link footer_who_we_are_link menu_add_a_product_link menu_contribute_link menu_discover_link nutrient_levels_link);
+my @slug_links
+ = qw(footer_code_of_conduct_link footer_data_link footer_faq_link footer_legal_link footer_press_link footer_terms_link footer_who_we_are_link menu_add_a_product_link menu_contribute_link menu_discover_link nutrient_levels_link);
test_links($slug_regex, @slug_links);
# check that footer links exist
@@ -48,7 +51,7 @@ foreach my $link (@links) {
my $textid = $Lang{$field}{$lang};
$textid =~ s/.*\///;
- if ($textid ne $en_links{$link} ) {
+ if ($textid ne $en_links{$link}) {
# Skip the following test, as the /lang directory now is in a separate openfoodfacts-web repository
# We will need to handle local text URLs differently, see https://github.com/openfoodfacts/openfoodfacts-server/issues/1818
@@ -57,20 +60,21 @@ foreach my $link (@links) {
}
-
}
}
-is( $Lang{months}{en}, "[\"January\",\"February\",\"March\",\"April\",\"May\",\"June\",\"July\",\"August\",\"September\",\"October\",\"November\",\"December\"]" );
-is( $Lang{weekdays}{en}, "[\"Sunday\",\"Monday\",\"Tuesday\",\"Wednesday\",\"Thursday\",\"Friday\",\"Saturday\"]" );
+is($Lang{months}{en},
+ "[\"January\",\"February\",\"March\",\"April\",\"May\",\"June\",\"July\",\"August\",\"September\",\"October\",\"November\",\"December\"]"
+);
+is($Lang{weekdays}{en}, "[\"Sunday\",\"Monday\",\"Tuesday\",\"Wednesday\",\"Thursday\",\"Friday\",\"Saturday\"]");
# https://github.com/openfoodfacts/openfoodfacts-server/issues/1116
sub test_logo_exists {
my $logo = shift;
foreach my $lang (keys %{$Lang{$logo}}) {
my $path = "$www_root/images/misc/$Lang{$logo}{$lang}";
- ok( -e $path, "file '$path' exists");
+ ok(-e $path, "file '$path' exists");
}
return;
@@ -85,6 +89,7 @@ foreach my $stringid (sort keys %Lang) {
while ($Lang{$stringid}{en} =~ /\{([^}]+)\}/g) {
my $variable = $1;
foreach my $l (sort keys %{$Lang{$stringid}}) {
+
# Note: the if below is added so that we don't have thousands of tests reported in the output
# only non passing tests are tested with like() and reported.
if ($Lang{$stringid}{$l} !~ /\{$variable\}/) {
diff --git a/taxonomies/categories.txt b/taxonomies/categories.txt
index 571d1a8a2cebc..e72d57ef38c47 100644
--- a/taxonomies/categories.txt
+++ b/taxonomies/categories.txt
@@ -39536,7 +39536,6 @@ protected_name_type:en: pgi
origins:en: en:France
[% lang("knowledge_panels_facts") %]
+
+- [% lang('nutrient_info_salt_risk') %]
+- [% lang('nutrient_info_salt_high_blood_pressure') %]
+- [% lang('nutrient_info_salt_high_consumption') %]
+
+
+[% lang("knowledge_panels_recommendation") %][% sep %]:
+[% lang('nutrient_recommendation_salt_title') %]
+
+- [% lang('nutrient_recommendation_salt_cooking_and_table') %]
+- [% lang('nutrient_recommendation_salt_limit_salty_snacks') %]
+
+`,
+ }
+ },
+ {
+ "element_type": "text",
+ "text_element": {
+ "type": "summary",
+ "html":
+`
+`,
+ "source_text": "World Health Organization (WHO) - Fact sheet - Salt reduction",
+ "source_url": "https://www.who.int/news-room/fact-sheets/detail/salt-reduction",
+ "source_language": "en",
+ }
+ },
+ {
+ "element_type": "text",
+ "text_element": {
+ "type": "summary",
+ "html":
+`
+`,
+ "source_text": "National Health Service UK (NHS) - Salt: the facts",
+ "source_url": "https://www.nhs.uk/live-well/eat-well/food-types/salt-nutrition/",
+ "source_language": "en",
+ }
+ },
+
+ [% END %]
+
+ [% IF panel.nid == 'sugars' %]
+ {
+ "element_type": "text",
+ "text_element": {
+ "type": "summary",
+ "html":
+`
+[% lang("knowledge_panels_facts") %]
+
+- [% lang('nutrient_info_sugars_risk') %]
+
+
+[% lang("knowledge_panels_recommendation") %][% sep %]:
+[% lang('nutrient_recommendation_sugars_title') %]
+
+- [% lang('nutrient_recommendation_sugars_drinks') %]
+- [% lang('nutrient_recommendation_sugars_food') %]
+
+`,
+ }
+ },
+ {
+ "element_type": "text",
+ "text_element": {
+ "type": "summary",
+ "html":
+`
+`,
+ "source_text": "National Health Service UK (NHS) - Sugar: the facts",
+ "source_url": "https://www.nhs.uk/live-well/eat-well/food-types/how-does-sugar-in-our-diet-affect-our-health/",
+ "source_language": "en",
+ }
+ },
+
+ [% END %]
+
+ [% IF panel.nid == 'fat'|| panel.nid == 'saturated-fat' %]
+ {
+ "element_type": "text",
+ "text_element": {
+ "type": "summary",
+ "html":
+`
+[% lang("knowledge_panels_facts") %]
+
+- [% lang('nutrient_info_fat_and_saturated_fat_risk') %]
+
+
+[% lang("knowledge_panels_recommendation") %][% sep %]:
+[% lang('nutrient_recommendation_fat_and_saturated_fat_title') %]
+
+- [% lang('nutrient_recommendation_fat_and_saturated_fat') %]
+
+`,
+ }
+ },
+ {
+ "element_type": "text",
+ "text_element": {
+ "type": "summary",
+ "html":
+`
+`,
+ "source_text": "National Health Service UK (NHS) - Fat: the facts",
+ "source_url": "https://www.nhs.uk/live-well/eat-well/food-types/different-fats-nutrition/",
+ "source_language": "en",
+ }
+ },
+
+ [% END %]
+ ]
+}
+
+
+
+
diff --git a/templates/web/pages/product/includes/nutrient_levels.tt.html b/templates/web/pages/product/includes/nutrient_levels.tt.html
index ea6028bdd671b..d888a9e0e9c84 100755
--- a/templates/web/pages/product/includes/nutrient_levels.tt.html
+++ b/templates/web/pages/product/includes/nutrient_levels.tt.html
@@ -9,7 +9,7 @@ [% lang('nutrient_levels_info') %]
[% FOREACH level IN nutrient_levels %]
[% level.nutriment_prepared %] g [% level.nutriment_quantity %]
+ alt="[% lang('${level.nutrient_level}_quantity') %]"> [% level.nutrient_quantity_in_grams %] g [% level.nutrient_bold_in_quantity %]
[% END %]
\ No newline at end of file