openfoodfoundation / openfoodnetwork

Connect suppliers, distributors and consumers to trade local produce.
https://www.openfoodnetwork.org
GNU Affero General Public License v3.0
1.12k stars 724 forks source link

When an article is setup by "item", if the quantity is more than one in the variant, the plural is not applied anymore #4172

Closed myriamboure closed 4 years ago

myriamboure commented 5 years ago

Description

I remember that before v2, when a product was sold per "item", if the variant was for example "2 items", and the name of the item was "piece", it was displayed as "2 pieces" by default (with a s for plural). It is not anymore in v2.

Expected Behavior

If sold per item, if quantity more than 1, plural should be applied automatically

Actual Behaviour

It is not

Steps to Reproduce

  1. Go to products page, setup a product per item, with two variants, put 2 as a quantity for the second and see, the item name is not plural

Animated Gif/Screenshot

Capture du 2019-08-20 13-36-11

Context

I saw that when doing customer support via skype screen sharing and noticed it.

Severity

bug-s3: a feature is broken but there is a workaround : we can manually write the display as field but we need to do it for every plural quantity, need to think about it...

Your Environment

Possible Fix

luisramos0 commented 5 years ago

I investigated this curious bug.

We have duplicated code to define display_as value of variants, it's called option_value_namer.

We have a version in ruby on the backend and a very similar (must have been copied) version of it in angular 🤕 Ruby: http://github.com/openfoodfoundation/openfoodnetwork/tree/master/lib/open_food_network/option_value_namer.rb Angular: https://github.com/openfoodfoundation/openfoodnetwork/blob/master/app/assets/javascripts/admin/products/services/option_value_namer.js.coffee

The problem is that they are not exactly the same, i.e., the required pluralization is only done on the Ruby code. We must have been using the ruby code before and now we are using the angular code (I confirmed that we are indeed using the angular code now).

There's a TODO entry to add pluralization to the angular code: that's exactly what this issue is!

I am tagging this a good first issue, note: javascript/coffeescript

luisramos0 commented 4 years ago

I was trying to find a way to make this pluralized unit name come from the server again and remove this code but it's too much trouble, it's complicated. I think we can just add the pluralization logic to the angular code as is. Maybe we can use this library: https://github.com/blakeembrey/pluralize

mkllnk commented 4 years ago

Hm, that pluralize library seems to only know English. Trying to apply English pluralisation rules to German words would make this worse.

Using server side translations may not help either:

You must define your own inflection rules for languages other than English. https://api.rubyonrails.org/classes/String.html

mkllnk commented 4 years ago

I had a good look into this and found:

My conclusions are that we can't rely on a library to get this right and that it may be harmful if it tries to pluralise things it doesn't know. Requiring a developer to program new inflection rules or add irregular words is too much maintenance for this little feature.

I came up with a relatively simple way to manage plurals within Transifex. We take the most popular unit names and add them to our language file as singular and plural. Both singular and plural can then get translated. Our code can look up if a unit name is in the dictionary and choose the right word. If it doesn't find it in the dictionary, it just leaves it as is.

mkllnk commented 4 years ago

@RachL

I extracted all used unit names from the French server. Can you check which ones are the most important to be pluralised? We can then cross-check with the English words to see if we need to add more.

French unit names with usage count ``` "pièce"=>365, "paquet"=>226, "pot"=>150, "botte"=>148, "bouteille"=>132, "flacon"=>51, "Pièce"=>47, "1"=>44, "Poids(Kg)"=>43, "fourchette de poids"=>42, "sachet"=>42, "Pièces"=>38, "panier"=>38, "plant"=>32, "boite"=>28, "piece"=>27, "pièces"=>25, "g"=>20, "sac"=>19, "bouquet"=>18, "carton de 20kg"=>16, "Botte"=>16, "bocal"=>15, "Panier"=>15, "kg"=>15, "paquet 500g"=>13, "pack"=>13, "tablette"=>13, "yaourt"=>13, "crottin"=>12, "pain"=>12, "Pièce "=>11, "oeufs"=>11, "biere"=>10, "fromage"=>10, "caisse"=>10, "bouteille 75 cl"=>9, "barquette"=>9, "Tranches"=>8, "unité"=>8, "chou"=>8, "bougie"=>8, "boîte"=>8, "pot 500g"=>7, "caisse de 5 kg"=>7, "sac de 5kg"=>7, "33cl"=>7, "bière de 33cl"=>7, "Pot"=>7, "pz"=>7, "Bouteille 33cl"=>6, "Caisse"=>6, "Bouteille 75cl"=>6, "chipo"=>6, "brique"=>6, "barre 60g"=>6, "PIECE"=>6, "pot 750g"=>6, "sachet sous vide"=>6, "env. 350g"=>6, "pot 240g"=>6, "Poulet"=>5, "personne(s)"=>5, "pot 260g"=>5, "Bocal 650 g"=>5, "1 pièce"=>5, "pacchetti da 250g"=>5, "Bouquet"=>5, "Bouteille"=>5, "coffret"=>5, "Pot 1 kg"=>5, "savon"=>5, "Sachets"=>5, "75cl"=>5, "Pot 500 g"=>5, "Unité"=>5, "Bouteilles"=>4, "env. 950g"=>4, "courgette (~200g)"=>4, "taglio da 500g ca"=>4, "sachet 100g"=>4, "Salade"=>4, "pots de 125g"=>4, "pot 90g"=>4, "Personne"=>4, "saucisse"=>4, "OEUFS"=>4, "carton de 10kg"=>4, "sachet de 200g"=>4, "125 g"=>4, "Bocal 180 g"=>4, "Bocal 350 g"=>4, "Caissette"=>4, "pot de 275g"=>4, "Piece"=>4, "os"=>4, "part"=>4, "bouquets"=>4, "colis"=>4, "courge"=>4, "sorbets 950ml"=>4, "sorbets 470ml"=>4, "4"=>4, "salade"=>4, "conserve"=>4, "pot 250 g"=>4, "carton de 12 bouteilles"=>3, "bouteille 75cl"=>3, "0, 1"=>3, "sac 5 kgs"=>3, "Pot 125 g"=>3, "savons"=>3, "morceau"=>3, "pot 20g"=>3, "pain 500g"=>3, "env. 400g"=>3, "yaourts de 125 g."=>3, "tranche"=>3, "Bouquet "=>3, "Bocal - 180g"=>3, "boîte de 6"=>3, "Barquette 500g"=>3, "élément"=>3, "unités"=>3, "Sachet"=>3, "paquet 100g"=>3, "galette"=>3, "plaquette"=>3, "pot 190g"=>3, "ficelle"=>3, "bouteille 1L"=>3, "Boîte"=>3, "50 g"=>3, "pot 500 g"=>3, "6x75cl"=>3, "caisse de 10 kg"=>3, "boite de 6"=>3, "100 g"=>3, "pot 210g"=>3, "pain 1 kg"=>3, "Flacon"=>3, "unite"=>3, "fourchette"=>3, "bocal (110g)"=>3, "BOTTE"=>3, "piéce"=>3, "b"=>3, "bidon"=>2, "pot 380g"=>2, "palet"=>2, "BIB"=>2, "sachet de 100g"=>2, "Bocal - 130g"=>2, "butternut"=>2, "pot 180g"=>2, "Sachet sous vide"=>2, "artichaut"=>2, "bib"=>2, "muffin"=>2, "galet"=>2, "personne"=>2, "345g"=>2, "carton (vide)"=>2, "tranches"=>2, "piment"=>2, "bocal de 340g"=>2, "sachet 2.5 kg"=>2, "pce"=>2, "carton de 25 sachets"=>2, "caissette"=>2, "pot 340g"=>2, "carton"=>2, "Navet"=>2, "tomme"=>2, "barre 80g"=>2, "env. 450g"=>2, "Bocal - 100g"=>2, "filet"=>2, "pieds"=>2, "chorizo"=>2, "Tomme"=>2, "cialde da 7g"=>2, "bouteille de 75 cl"=>2, "concombre"=>2, "Douzaines"=>2, "Kg"=>2, "bouteille de 20 cl"=>2, "paniers"=>2, "melon"=>2, "carton de 15 pots"=>2, "plaque"=>2, "6 pièces"=>2, "chou fleur"=>2, "colis 3 kg"=>1, "pots de 100g"=>1, "carton de 24 bouteilles"=>1, "bouteille (75cl)"=>1, "potimarron"=>1, "BOUTEILLE"=>1, "paquet de 2"=>1, "bouteille1 litre"=>1, "caissette 6kg"=>1, "12 pièces"=>1, "185g"=>1, "grand panier"=>1, "Fondant 250g"=>1, "riz au lait"=>1, "barre 100g"=>1, "pain 700g"=>1, "2 cuisses"=>1, "litre"=>1, "pièce de 0.800g à 1.2kg"=>1, "betterave ~250gr"=>1, "yaourts"=>1, "95-105g"=>1, "Radis noir"=>1, "Avocat"=>1, "900"=>1, "Bocal 4 Dz"=>1, "pain-sans-gluten-aux-dattes"=>1, "oignon"=>1, "Botte (1kg)"=>1, "tomate(s) 500g"=>1, "Blette"=>1, "Sac de 10kg"=>1, "pacchettida 250g"=>1, "115g"=>1, "paquet de 3 diots"=>1, "600g"=>1, " filet"=>1, "épi"=>1, "bouteille 0, 5 L de 50cl"=>1, "Pot 180 g"=>1, "4 cuisses"=>1, "pot 95g"=>1, "Terrine"=>1, "paquet 160g"=>1, "sceau"=>1, "gâteau"=>1, "pa"=>1, "Pacco da 500g"=>1, "boîte de 6 oeufs BIO"=>1, "Sac"=>1, "pass"=>1, "colis de 10 kg (prix au kg)"=>1, "citron"=>1, "portions"=>1, "pot de 110 g"=>1, "bidon de 5L"=>1, "paquet 1kg"=>1, "300g"=>1, "pot 200g"=>1, "saucissons"=>1, "kiwano"=>1, "Barquette 250g"=>1, "bouteille 690g"=>1, "pot 150g"=>1, "env. 800gr"=>1, "Laitue"=>1, "dôme"=>1, "Bocal 2 Dz"=>1, "Barquette de 20 fleurs"=>1, "patidou"=>1, "Pocsav"=>1, "Boite"=>1, "par caisse"=>1, "réglette"=>1, "1 unité"=>1, "sachet 30 g"=>1, "colis de 7 à 9 kg (prix indicatif pour 8kg)"=>1, "pot de 100 g"=>1, "pyramide"=>1, "sachet 2 X 7g"=>1, "dessert"=>1, " feuilles"=>1, "brunch"=>1, "Rôti "=>1, "artichaud"=>1, "Brassard"=>1, "Sac de 5 kg"=>1, "carton de 50 sachets"=>1, "quartier (env.900g)"=>1, "Tommette"=>1, "boisson"=>1, "1 lot de 5"=>1, "Pied"=>1, "confiture prunes"=>1, "kit de production de pleurotes"=>1, "paquet de 500-600 g"=>1, "formule"=>1, "Bib"=>1, "pot 170g"=>1, "cagette"=>1, "fromage frais"=>1, "env. 800g"=>1, "1/4 de jambon environ 1.200Kg"=>1, "orange"=>1, "flacon 750ml"=>1, "caisse 14 kg"=>1, "valisette"=>1, "seau 2kg"=>1, "bocal 180g"=>1, "filet 5 kg"=>1, "Sac de 10 kg"=>1, "petits pains sans gluten à l'huile d'olive"=>1, "bocal de 690g"=>1, "env. 900g"=>1, "pot 160g"=>1, "6x160 g"=>1, "paquet de 100g"=>1, "ananas"=>1, "verre"=>1, "filmé"=>1, "pot de 280 g"=>1, "195g"=>1, "20cl"=>1, "boîte de 20 sachets"=>1, "saucisson 240g"=>1, "Sachet 2.5 kg"=>1, "tete"=>1, "lot de 5 x 250g"=>1, "Bocal 5 douzaines Calibre Belle Grosseur"=>1, "colis de 8kg env"=>1, "g net"=>1, "22"=>1, "colis maxi 5, 5kg"=>1, "pot de 230g"=>1, "pack de 6 rouleaux"=>1, "flacon 1L"=>1, "100g"=>1, "Affiné"=>1, "200ml"=>1, "kit"=>1, "lingette"=>1, "4x160 g"=>1, "caisse 13 kg"=>1, "Tommette génépi"=>1, "ballot"=>1, "24cl"=>1, "6 oeufs"=>1, "3x33cl"=>1, "25cl"=>1, "laitue"=>1, "Boite 340g"=>1, "5 kg"=>1, "sac de 20 kg"=>1, "entrée"=>1, "lot de 20"=>1, "potimarion"=>1, "6 manchons"=>1, "barquette 250g"=>1, "bocal ( 110g)"=>1, "Grammes"=>1, "tomate 200g"=>1, "1 pot"=>1, "Sachet sous "=>1, "tranche "=>1, "colis de 7 kg environ (prix au kg)"=>1, "pour 1-2 pers."=>1, "paquet 120g"=>1, "plat"=>1, "tablettes"=>1, "env. 1kg - 1, 2kg"=>1, "1L"=>1, "pack de 2 rouleaux"=>1, "pot 280g"=>1, " sachet de 2 X 6g"=>1, "800 g"=>1, "bouteille de 25 cl"=>1, "pot 220g"=>1, "paquet de 500 g"=>1, "pain1 kg"=>1, "tomme de 500 g."=>1, "750g"=>1, "DEMI POULET"=>1, "ricotta"=>1, "tête"=>1, "jeton"=>1, "Oeuf"=>1, "pot 130g"=>1, "boîte 250g"=>1, "Bocal 3 douzaines Calibre Moyen"=>1, "€ de soutien à la communauté OpenFoodFrance"=>1, "portion"=>1, "carton de 8 bouteilles"=>1, "pack de 2 pots de yaourts"=>1, "Plateau"=>1, "fromage mi-frais"=>1, "Quart"=>1, "colis de 5 kg"=>1, "paquets de 500g"=>1, "bardé"=>1, "5 gésiers"=>1, "bouteille 25cLde 25cl"=>1, "Barquette de 3 pièces"=>1, "tranche (230g)"=>1, "X 2 pots"=>1, "bouteille 33 cl"=>1, "bouteilles"=>1, "Frais"=>1, "bouteille 33cl"=>1, "flacon de 500ml"=>1, "carton de 6"=>1, "Coffret"=>1, "pots de 150g"=>1, "pomelos (~500g)"=>1, "125 gr"=>1, "carton de 3 bidons"=>1, "carton de 9 bouteilles"=>1, "filet 5kg"=>1, "STUK"=>1, "brousse"=>1, "plantes"=>1, "cabas"=>1, "Courge"=>1, "Bocal 6 Dz"=>1, "500g"=>1, "fromage blanc (500g)"=>1, "400 g"=>1, "sachet de 145 g environ"=>1, "pains sans gluten"=>1, "confiture de fraises"=>1, "financier"=>1, "volaille"=>1, "Essuietout"=>1, "24x25cl"=>1, "Sac de 25kg"=>1, "endive"=>1, "little be jack"=>1, "250 gr"=>1, "x 4 Chipo"=>1, "sachet 25g"=>1, "mini patisson"=>1, "Sous Vide"=>1, "Carton 50 dz"=>1, "frais aux herbes"=>1, "verrine de 270g"=>1, "Artichaud"=>1, "env. 1-1.2kg"=>1, "bouteille de 35 cl"=>1, "brioche"=>1, "crêpes"=>1, "rouleau"=>1, "Carton 25 dz"=>1, "320 g"=>1, "demi-tomme"=>1, "crepes"=>1, "creme"=>1, "Bocal 6 douzaines Calibre Moyen"=>1, "Boite de 6"=>1, "pacchetto"=>1, "cidre"=>1, "poivron"=>1, "paquet sous vide"=>1, "pot 330g"=>1, "3x20cl"=>1, "150g"=>1, "Portion"=>1, "euro"=>1, "carrés"=>1, "sachet de 2 X 8g"=>1, "bûche"=>1, "1000"=>1, "Bocal 5 Dz"=>1, "truite"=>1, "KG"=>1, "Tranche (150g)"=>1, "75ml"=>1, "env. 850g"=>1, "sucrine"=>1, "les 6 tranches"=>1, "Barquette 250gr"=>1, "tranche (230g)s"=>1, "bocal de 500g"=>1, "pz (30mt)"=>1, "Confiture"=>1, "pot de 160g"=>1, "Citron"=>1, "Bocal 7 douzaines Calibre Petits"=>1, "botte de 3/4"=>1, "ml"=>1, "Tête"=>1, "Poulet de 1, 8kg environ"=>1, "Bouteille de 1 L"=>1, "bol"=>1, "nature"=>1, "sac de 1, 5 kg"=>1, "mache"=>1, "sac de 25 kg"=>1, "beignets"=>1, "pot de 210g"=>1, "Boite de mouchoir"=>1, "bouton"=>1, "Buchette 150g"=>1, "env. 480g"=>1, " pièce"=>1, "paquet de 8 pain"=>1, "jambon"=>1, "Boite "=>1, "côte"=>1, "coeur"=>1, "50cl"=>1, "Bocal 2 douzaines Calibre Belle Grosseur"=>1, "sac 3 kgs"=>1, "Chevrotin"=>1, "pot 120g"=>1, "pièce "=>1, "bouteille de 33cl"=>1, "quatre-quart"=>1, "1 fenouil"=>1, "Tome"=>1, "Bocal 150g"=>1, "250"=>1, "sac de 10 kg"=>1, "paquet de 10 étuis"=>1, "pot 18g"=>1, "Litre"=>1, "flacon de 15ml"=>1, "petit panier"=>1, "€ de soutien à la communauté \"Au Panier Rusé\""=>1, "poireaux"=>1, "700g"=>1, "Bocal 3 Dz"=>1, "panier bébé"=>1, "assiette"=>1, "Oeufs"=>1, "poulet"=>1, "flacon d'1L"=>1, "crêpe"=>1, "Chou"=>1, "mottais"=>1, "pot de 600g"=>1, "nems"=>1, "pizza"=>1, "pain 1 kg cuit dans un moule"=>1, "Valisette"=>1, "deux cotelettes sous vide d'un poids allant de 300 à 450g environ"=>1, "Boite de 12"=>1, "pastèque"=>1, "boite ou sachet"=>1, "flacon 500ml"=>1, "2 parts"=>1 ```
mkllnk commented 4 years ago

I realised that the Javascript is only used for the preview how the unit will be displayed. The result is not saved and not used in the shop or reports. The similar Ruby code is doing that and it hasn't been very good at that. For example, it's wrong in German: Screenshot from 2020-01-23 12-04-20

It should say 30 Stück or 30 Stücke but not 30 Stücks. That's not a word. So, in order to be consistent, we need a solution for Ruby and Javascript. I included that in my pull request.

RachL commented 4 years ago

@mkllnk here they are with their plural:

"pièce"=> pièces "paquet"=> paquets "pot"=> pots "botte"=> bottes "bouteille"=>bouteilles "flacon"=> flacons "Pièce"=> Pièces "sachet"=> sachets "panier"=> paniers "boite"=> boites "sac"=>sacs "bouquet"=> bouquets "Botte"=> Bottes "bocal"=> bocaux "Panier"=> Paniers "caisse"=> caisses "barquette"=> barquettes "unité"=> unités "boîte"=> boîtes

mkllnk commented 4 years ago

Ah, great @RachL. Can you also tell me what the English translation is?

RachL commented 4 years ago

@mkllnk

hehe I even learned a few things :)

"pièce"=> pièces pieces "paquet"=> paquets pack "pot"=> pots pot => but the stuff you use to put cream or plant inside, not the second meaning right ;) "botte"=> bottes bundles "bouteille"=>bouteilles bottles "flacon"=> flacons flacks "Pièce"=> Pièces pieces "sachet"=> sachets bags "panier"=> paniers baskets "boite"=> boites boxes "sac"=>sacs bags "bouquet"=> bouquets bunch "Botte"=> Bottes bundles "bocal"=> bocaux jars "Panier"=> Paniers baskets "caisse"=> caisses crates "barquette"=> barquettes trays "unité"=> unités units "boîte"=> boîtes boxes

mkllnk commented 4 years ago

@RachL

"flacon"=> flacons flacks

Do you mean flask?

RachL commented 4 years ago

@mkllnk ahem. Yes. 🤦‍♂