Index: compile_rules_graph.py ================================================================== --- compile_rules_graph.py +++ compile_rules_graph.py @@ -164,11 +164,11 @@ sOption = m.group(1) sAction = sAction[m.end():].strip() if nPriority == -1: nPriority = dOptPriority.get(sOption, 4) # valid action? - m = re.search(r"(?P[-~=/%>])(?P-?\d+\.?|)(?P:\.?-?\d+|)>>", sAction) + m = re.search(r"(?P[-~=/%>])(?P-?\d+\.?|)(?P:\.?-?\d+|)(?P:|)>>", sAction) if not m: print(" # Error. No action found at: ", sActionId) return None # Condition sCondition = sAction[:m.start()].strip() @@ -177,10 +177,12 @@ sCondition = prepareFunction(sCondition) dFUNCTIONS["_g_c_"+sActionId] = sCondition sCondition = "_g_c_"+sActionId else: sCondition = "" + # Case sensitivity + bCaseSensitivity = False if m.group("casing") == ":" else True # Action cAction = m.group("action") sAction = sAction[m.end():].strip() sAction = changeReferenceToken(sAction, dPos) # target @@ -260,20 +262,20 @@ sAction = "=_g_s_"+sActionId elif sAction.startswith('"') and sAction.endswith('"'): sAction = sAction[1:-1] if not sMsg: print("# Error in action at line " + sActionId + ": The message is empty.") - return [sOption, sCondition, cAction, sAction, iStartAction, iEndAction, cStartLimit, cEndLimit, nPriority, sMsg, sURL] + return [sOption, sCondition, cAction, sAction, iStartAction, iEndAction, cStartLimit, cEndLimit, bCaseSensitivity, nPriority, sMsg, sURL] elif cAction == "~": ## text processor if sAction[0:1] == "=": sAction = prepareFunction(sAction) dFUNCTIONS["_g_p_"+sActionId] = sAction[1:] sAction = "=_g_p_"+sActionId elif sAction.startswith('"') and sAction.endswith('"'): sAction = sAction[1:-1] - return [sOption, sCondition, cAction, sAction, iStartAction, iEndAction] + return [sOption, sCondition, cAction, sAction, iStartAction, iEndAction, bCaseSensitivity] elif cAction == "%" or cAction == "/": ## tags return [sOption, sCondition, cAction, sAction, iStartAction, iEndAction] elif cAction == "=": ## disambiguator Index: gc_core/py/lang_core/gc_engine.py ================================================================== --- gc_core/py/lang_core/gc_engine.py +++ gc_core/py/lang_core/gc_engine.py @@ -772,37 +772,37 @@ for sRuleId in dGraph[nextNodeKey]: try: if bDebug: print(" TRY:", sRuleId) sOption, sFuncCond, cActionType, sWhat, *eAct = dRule[sRuleId] - # Suggestion [ option, condition, "-", replacement/suggestion/action, iTokenStart, iTokenEnd, cStartLimit, cEndLimit, nPriority, sMessage, sURL ] - # TextProcessor [ option, condition, "~", replacement/suggestion/action, iTokenStart, iTokenEnd ] + # Suggestion [ option, condition, "-", replacement/suggestion/action, iTokenStart, iTokenEnd, cStartLimit, cEndLimit, bCaseSvty, nPriority, sMessage, sURL ] + # TextProcessor [ option, condition, "~", replacement/suggestion/action, iTokenStart, iTokenEnd, bCaseSvty ] # Disambiguator [ option, condition, "=", replacement/suggestion/action ] # Sentence Tag [ option, condition, "/", replacement/suggestion/action, iTokenStart, iTokenEnd ] # Test [ option, condition, ">", "" ] if not sOption or dOptions.get(sOption, False): bCondMemo = not sFuncCond or globals()[sFuncCond](self.lToken, nTokenOffset, nLastToken, sCountry, bCondMemo, self.dTags, self.sSentence, self.sSentence0) if bCondMemo: if cActionType == "-": # grammar error - iTokenStart, iTokenEnd, cStartLimit, cEndLimit, nPriority, sMessage, sURL = eAct + iTokenStart, iTokenEnd, cStartLimit, cEndLimit, bCaseSvty, nPriority, sMessage, sURL = eAct nTokenErrorStart = nTokenOffset + iTokenStart if iTokenStart > 0 else nLastToken + iTokenStart if "bImmune" not in self.lToken[nTokenErrorStart]: nTokenErrorEnd = nTokenOffset + iTokenEnd if iTokenEnd > 0 else nLastToken + iTokenEnd nErrorStart = self.nOffsetWithinParagraph + (self.lToken[nTokenErrorStart]["nStart"] if cStartLimit == "<" else self.lToken[nTokenErrorStart]["nEnd"]) nErrorEnd = self.nOffsetWithinParagraph + (self.lToken[nTokenErrorEnd]["nEnd"] if cEndLimit == ">" else self.lToken[nTokenErrorEnd]["nStart"]) if nErrorStart not in self.dError or nPriority > dPriority.get(nErrorStart, -1): - self.dError[nErrorStart] = self._createError(sWhat, nTokenOffset, nLastToken, nTokenErrorStart, nErrorStart, nErrorEnd, sLineId, sRuleId, True, sMessage, sURL, bShowRuleId, "notype", bContext) + self.dError[nErrorStart] = self._createError(sWhat, nTokenOffset, nLastToken, nTokenErrorStart, nErrorStart, nErrorEnd, sLineId, sRuleId, bCaseSvty, sMessage, sURL, bShowRuleId, "notype", bContext) dPriority[nErrorStart] = nPriority if bDebug: print(" NEW_ERROR:", self.dError[nErrorStart], "\n ", dRule[sRuleId]) elif cActionType == "~": # text processor if bDebug: print(" TAG_PREPARE:\n ", dRule[sRuleId]) nEndToken = (nTokenOffset + eAct[1]) if eAct[1] else nLastToken - self._tagAndPrepareTokenForRewriting(sWhat, nTokenOffset + eAct[0], nEndToken, nTokenOffset, nLastToken, True, bDebug) + self._tagAndPrepareTokenForRewriting(sWhat, nTokenOffset + eAct[0], nEndToken, nTokenOffset, nLastToken, eAct[2], bDebug) bChange = True elif cActionType == "=": # disambiguation if bDebug: print(" DISAMBIGUATOR:\n ", dRule[sRuleId]) @@ -839,20 +839,20 @@ break except Exception as e: raise Exception(str(e), sLineId, sRuleId, self.sSentence) return bChange - def _createError (self, sSugg, nTokenOffset, nLastToken, iFirstToken, nStart, nEnd, sLineId, sRuleId, bUppercase, sMsg, sURL, bShowRuleId, sOption, bContext): + def _createError (self, sSugg, nTokenOffset, nLastToken, iFirstToken, nStart, nEnd, sLineId, sRuleId, bCaseSvty, sMsg, sURL, bShowRuleId, sOption, bContext): # suggestions if sSugg[0:1] == "=": sSugg = globals()[sSugg[1:]](self.lToken, nTokenOffset, nLastToken) lSugg = sSugg.split("|") if sSugg else [] elif sSugg == "_": lSugg = [] else: lSugg = self._expand(sSugg, nTokenOffset, nLastToken).split("|") - if bUppercase and lSugg and self.lToken[iFirstToken]["sValue"][0:1].isupper(): + if bCaseSvty and lSugg and self.lToken[iFirstToken]["sValue"][0:1].isupper(): lSugg = list(map(lambda s: s[0:1].upper()+s[1:], lSugg)) # Message sMessage = globals()[sMsg[1:]](self.lToken, nTokenOffset) if sMsg[0:1] == "=" else self._expand(sMsg, nTokenOffset, nLastToken) if bShowRuleId: sMessage += " " + sLineId + " # " + sRuleId @@ -900,11 +900,11 @@ else: sText = sText.replace(m.group(0), self.lToken[nTokenOffset+int(m.group(1))]["sValue"]) #print(">", sText) return sText - def _tagAndPrepareTokenForRewriting (self, sWhat, nTokenRewriteStart, nTokenRewriteEnd, nTokenOffset, nLastToken, bUppercase=True, bDebug=False): + def _tagAndPrepareTokenForRewriting (self, sWhat, nTokenRewriteStart, nTokenRewriteEnd, nTokenOffset, nLastToken, bCaseSvty, bDebug): "text processor: rewrite tokens between and position" if bDebug: print(" START:", nTokenRewriteStart, "END:", nTokenRewriteEnd) if sWhat == "*": # purge text @@ -933,11 +933,11 @@ else: if sWhat.startswith("="): sWhat = globals()[sWhat[1:]](self.lToken, nTokenOffset) else: sWhat = self._expand(sWhat, nTokenOffset, nLastToken) - bUppercase = bUppercase and self.lToken[nTokenRewriteStart]["sValue"][0:1].isupper() + bUppercase = bCaseSvty and self.lToken[nTokenRewriteStart]["sValue"][0:1].isupper() if nTokenRewriteEnd - nTokenRewriteStart == 0: # one token sWhat = sWhat + " " * (len(self.lToken[nTokenRewriteStart]["sValue"])-len(sWhat)) if bUppercase: sWhat = sWhat[0:1].upper() + sWhat[1:] Index: gc_lang/fr/rules.grx ================================================================== --- gc_lang/fr/rules.grx +++ gc_lang/fr/rules.grx @@ -6369,11 +6369,11 @@ # Les jours __maj_jours_semaine__ [*WORD|*NUM] [Lundi|Mardi|Mercredi|Jeudi|Vendredi|Samedi|Dimanche] , [Lundi|Mardi|Mercredi|Jeudi|Vendredi|Samedi|Dimanche] - <<- /maj/ -2>> =\2.lower() + <<- /maj/ -2:>> =\2.lower() # Pas de majuscule sur les jours de la semaine.|http://www.academie-francaise.fr/la-langue-francaise/questions-de-langue#42_strong-em-jours-de-la-semaine-pluriel-et-majuscules-em-strong TEST: Nous vous donnons rendez-vous {{Mercredi}} le 18. @@ -6382,21 +6382,21 @@ monarchie de Juillet révolution d’ Octobre <<- ~3>> ! *WORD [Janvier|Février|Avril|Mai|Juin|Juillet|Août|Aout|Septembre|Octobre|Novembre|Décembre|Vendémiaire|Brumaire|Frimaire|Nivôse|Pluviôse|Ventôse|Germinal|Floréal|Prairial|Messidor|Thermidor|Fructidor] - <<- /maj/ not morph(\1, ":M1") -2>> =\2.lower() + <<- /maj/ not morph(\1, ":M1") -2:>> =\2.lower() # Pas de majuscule sur les mois.|http://www.academie-francaise.fr/la-langue-francaise/questions-de-langue#42_strong-em-jours-de-la-semaine-pluriel-et-majuscules-em-strong [*NUM|*WORD_ELIDED] [Janvier|Février|Avril|Mai|Juin|Juillet|Août|Aout|Septembre|Octobre|Novembre|Décembre|Vendémiaire|Brumaire|Frimaire|Nivôse|Pluviôse|Ventôse|Germinal|Floréal|Prairial|Messidor|Thermidor|Fructidor] , [Janvier|Février|Avril|Mai|Juin|Juillet|Août|Aout|Septembre|Octobre|Novembre|Décembre|Vendémiaire|Brumaire|Frimaire|Nivôse|Pluviôse|Ventôse|Germinal|Floréal|Prairial|Messidor|Thermidor|Fructidor] - <<- /maj/ -2>> =\2.lower() + <<- /maj/ -2:>> =\2.lower() # Pas de majuscule sur les mois.|http://www.academie-francaise.fr/la-langue-francaise/questions-de-langue#42_strong-em-jours-de-la-semaine-pluriel-et-majuscules-em-strong [1|2|3|4|5|6|7|8|9|01|02|03|04|05|06|07|08|09|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31] Mars en Mars - <<- /maj/ -2>> mars + <<- /maj/ -2:>> mars # Pas de majuscule sur les mois.|http://www.academie-francaise.fr/la-langue-francaise/questions-de-langue#42_strong-em-jours-de-la-semaine-pluriel-et-majuscules-em-strong TEST: 15 {{Septembre}} ->> septembre TEST: 23 {{Messidor}} ->> messidor TEST: ils viendront en {{Mars}}. ->> mars @@ -6441,11 +6441,11 @@ océan Indien [îles|iles] Britanniques <<- ~2>> ! *WORD [>afghane|>albanaise|>algérienne|>allemande|>américaine|>andorrane|>anglais|>angolaise|>arabe|>argentine|>arménienne|>australienne|>autrichienne|>asiatique|>azerbaïdjanaise|>bahamienne|>bangladaise|>bengladeshie|>barbadienne|>basque|>belge|>bélizienne|>béninoise|>bretonne|>bhoutanaise|>biélorusse|>birmane|>bolivienne|>bosnienne|>botswanaiso|>brésilienne|>britannique|>brunéiene|>bulgare|>burkinabé|>burundaise|>cambodgienne|>camerounaise|>canadienne|>capverdienne|>centrafricaine|>chilienne|>chinoise|>chypriote|>colombienne|>comorienne|>congolaise|>nord-coréenne|>corse|>costaricienne|>croate|>cubaine|>danoise|>djiboutienne|>dominicaine|>égyptienne|>émiratie|>équatorienne|>érythréenne|>estonienne|>espagnole|>étatsunienne|>états-unienne|>étasunienne|>éthiopienne|>fidjienne|>finlandaise|>formosane|>française|>gabonaise|>gambienne|>géorgienne|>ghanéenne|>grecque|>grenadienne|>guadeloupéenne|>guatémaltèque|>guinéenne|>équato-guinéenne|>guyanienne|>haïtienne|>honduriene|>hollandaise|>hongroise|>indienne|>indochinoise|>indonésienne|>irakienne|>italienne|>iranienne|>irlandaise|>islandaise|>israélienne|>ivoirienne|>jamaïcaine|>japonaise|>jordanienne|>kazakhe|>kényane|>kosovare|>koweïtienne|>laotienne|>lapone|>lettone|>libanaise|>libérienne|>libyenne|>liechtensteinoise|>lituanienne|>luxembourgeois|>macédonienne|>maghrébine|>malgache|>malaisienne|>malawite|>maldivienne|>malienne|>maltaise|>maorie|>marocaine|>martienne|>mauricienne|>mauritanienne|>mexicaine|>micronésienne|>moldave|>monégasque|>monténégrine|>mongole|>mozambicaine|>namibiene|>népalaise|>nicaraguayenne|>nigérienne|>nigériane|>néerlandaise|>norvégienne|>néo-zélandaise|>ougandaise|>ouzbèke|>pakistanaise|>palestinienne|>panaméenne|>paraguayenne|>perse|>péruvienne|>philippine|>polonaise|>polynésienne|>portugaise|>québécoise|>qatarie|>roumaine|>russe|>rwandaise|>saoudienne|>scandinave|>salvadorienne|>sénégalaise|>serbe|>singapourienne|>slovaque|>slovène|>somalienne|>soudanaise|>soviétique|>srilankaise|>suédoise|>suisse|>surinamaise|>syrienne|>sud-africaine|>sud-coréenne|>américaine|>tadjike|>tanzanienne|>tchadienne|>tchèque|>thaïlandaise|>togolaise|>tahitienne|>tunisiene|>turkmène|>turque|>taïwanaise|>ukrainienne|>uruguayenne|>vénézuélienne|>vietnamienne|>yéménite|>yougoslave|>zaïroise|>zambienne|>zimbabwéenne] - <<- /maj/ \2.istitle() and morph(\1, ":N", ":(?:A|V0e|D|R|B)") -2>> =\2.lower() # S’il s’agit d’un adjectif, ne mettez pas de majuscule. + <<- /maj/ \2.istitle() and morph(\1, ":N", ":(?:A|V0e|D|R|B)") -2:>> =\2.lower() # S’il s’agit d’un adjectif, ne mettez pas de majuscule. <<- /maj/ \2.islower() and not \2.startswith("canadienne") and ( value(\1, "|certains|certaines|ce|cet|cette|ces|des|les|nos|vos|leurs|quelques|plusieurs|chaque|une|aux|") or ( value(\1, "|un|") and not value(<1, "|dans|numéro|") and not after("(?:approximatif|correct|courant|parfait|facile|aisé|impeccable|incompréhensible)") ) ) -2>> =\2.capitalize() # S’il s’agit d’un gentilé, mettez une majuscule. @@ -6466,14 +6466,14 @@ # les langues __maj_langues__ [>parler|cours|>leçon|>apprendre|>étudier|>traduire|>enseigner|>professeure|>enseignante|>dictionnaire|>méthode] [le|de|du|l’|d’|que|qu’|qu] [Afrikaans|Albanais|Allemand|Alsacien|Anglais|Arabe|Aragonais|Arménien|Asturien|Basque|Bengali|Biélorusse|Birman|Bosniaque|Breton|Bulgare|Cantonais|Catalan|Cherokee|Chinois|Corse|Cornique|Coréen|Croate|Danois|Écossais|Espagnol|Espéranto|Estonien|Féroïen|Farsi|Finnois|Flamand|Français|Frison|Galicien|Gallois|Gaulois|Géorgien|Grec|Gujarati|Hakka|Hawaïen|Hébreu|Hindi|Hollandais|Hongrois|Javanais|Ido|Indonésien|Interlingua|Islandais|Italien|Irlandais|Japonais|Kazakh|Khmer|Kurde|Ladino|Laotien|Latin|Ligurien|Limbourgeois|Lituanien|Lombard|Luxembourgeois|Macédonien|Malais|Maldivien|Malgache|Maltais|Mandarin|Maori|Marathi|Marwari|Moldave|Mongol|Napolitain|Néerlandais|Norvégien|Occitan|Ourdou|Ouzbek|Persan|Peul|Piémontais|Polonais|Portugais|Provençal|Quichua|Romanche|Roumain|Russe|Sans[ck]rit|Sarde|Serbe|Sicilien|Sindhi|Slovaque|Slovène|Soudanais|Sorabe|Suédois|Swahili|Tagalog|Tahitien|Tamoul|Tatar|Tchèque|Thaï|Turc|Ukrainien|Vénitien|Vietnamien|Volapük|Wallon|Wou|Wu|Yiddish|Xhosa|Xiang|Zoulou] - <<- /maj/ -3>> =\3.lower() # Si vous parlez de la langue, pas de majuscule. + <<- /maj/ -3:>> =\3.lower() # Si vous parlez de la langue, pas de majuscule. en [Afrikaans|Albanais|Allemand|Alsacien|Anglais|Arabe|Aragonais|Arménien|Asturien|Basque|Bengali|Biélorusse|Birman|Bosniaque|Breton|Bulgare|Cantonais|Catalan|Cherokee|Chinois|Cornique|Coréen|Croate|Danois|Écossais|Espagnol|Espéranto|Estonien|Féroïen|Farsi|Finnois|Flamand|Français|Frison|Galicien|Gallois|Gaulois|Géorgien|Grec|Gujarati|Hakka|Hawaïen|Hébreu|Hindi|Hollandais|Hongrois|Javanais|Ido|Indonésien|Interlingua|Islandais|Italien|Irlandais|Japonais|Kazakh|Khmer|Kurde|Ladino|Laotien|Latin|Ligurien|Limbourgeois|Lituanien|Lombard|Luxembourgeois|Macédonien|Malais|Maldivien|Malgache|Maltais|Mandarin|Maori|Marathi|Marwari|Moldave|Mongol|Napolitain|Néerlandais|Norvégien|Occitan|Ourdou|Ouzbek|Persan|Peul|Piémontais|Polonais|Portugais|Provençal|Quichua|Romanche|Roumain|Russe|Sans[ck]rit|Sarde|Serbe|Sicilien|Sindhi|Slovaque|Slovène|Soudanais|Sorabe|Suédois|Swahili|Tagalog|Tahitien|Tamoul|Tatar|Tchèque|Thaï|Turc|Ukrainien|Vénitien|Vietnamien|Volapük|Wallon|Wou|Wu|Yiddish|Xhosa|Xiang|Zoulou] - <<- /maj/ -2>> =\1.lower() # Si vous parlez de la langue, pas de majuscule. + <<- /maj/ -2:>> =\2.lower() # Si vous parlez de la langue, pas de majuscule. TEST: il ne parle qu’{{Allemand}}. TEST: ta traduction en {{Russe}} est superbe. @@ -6485,11 +6485,11 @@ <<- /maj/ ->> Moyen Âge # Le “Moyen Âge”, l’époque médiévale. moyen âge <<- /maj/ \1.islower() and \2.islower() ->> Moyen Âge # Le “Moyen Âge”, l’époque médiévale. -TEST: C’est le {{moyen age}}, chez ces ploucs. +TEST: C’est le {{moyen age}}, chez ces ploucs. ->> Moyen Âge # Église __maj_Église__ l’ église [adventiste|anglicane|copte|catholique|calviniste|épiscopalienne|jacobite|luthérienne|lutherienne|méthodiste|mormone|néo-apostolique|néoapostolique|orthodoxe|pentecôtiste|presbytérienne|protestante|réformée] @@ -6501,11 +6501,11 @@ [>chef|>rite|>sacrement] de l’ église <<- /maj/ \3.islower() -4>> Église # Lorsqu’on parle de l’institution, une majuscule est requise. Pour un bâtiment, pas de majuscule. [*WORD|*WORD_ELIDED] [Église|Églises] [>baroque|>gothique|>romane|~^Saint-[A-ZÉÊ]] , [Église|Églises] [>baroque|>gothique|>romane|~^Saint-[A-ZÉÊ]] - <<- /maj/ -2>> église # Pour un bâtiment, une minuscule est requise. La majuscule est pour l’institution. + <<- /maj/ -2:>> église # Pour un bâtiment, une minuscule est requise. La majuscule est pour l’institution. TEST: L’{{église}} orthodoxe. ->> Église TEST: un homme d’{{église}} ->> Église TEST: les sacrements de l’{{église}} ->> Église TEST: Une {{Église}} baroque. ->> église @@ -6530,11 +6530,11 @@ __maj_unités__ *NUM [Mètre|Watt|Gramme|Seconde|Ampère|Kelvin|Mole|Candela|Candéla|Hertz|Henry|Newton|Pascal|Joule|Coulomb|Volt|Ohm|Farad|Tesla|Weber|Wéber|Radian|Stéradian|Lumen|Lux|Becquerel|Gray|Sievert|Siemens|Katal|Mètres|Watts|Grammes|Secondes|Ampères|Kelvins|Moles|Candelas|Candélas|Hertz|Henrys|Newtons|Pascals|Joules|Coulombs|Volts|Ohms|Farads|Teslas|Webers|Wébers|Radians|Stéradians|Lumens|Becquerels|Grays|Sieverts|Katals] @:B [Mètre|Watt|Gramme|Seconde|Ampère|Kelvin|Mole|Candela|Candéla|Hertz|Henry|Newton|Pascal|Joule|Coulomb|Volt|Ohm|Farad|Tesla|Weber|Wéber|Radian|Stéradian|Lumen|Lux|Becquerel|Gray|Sievert|Siemens|Katal|Mètres|Watts|Grammes|Secondes|Ampères|Kelvins|Moles|Candelas|Candélas|Hertz|Henrys|Newtons|Pascals|Joules|Coulombs|Volts|Ohms|Farads|Teslas|Webers|Wébers|Radians|Stéradians|Lumens|Becquerels|Grays|Sieverts|Katals] *NUM ~(?:Exa|P[ée]ta|Téra|Giga|Méga|Kilo|Hecto|Déc[ai]|Centi|Milli|Micro|Nano|Pico|Femto|Atto|Ze(?:pto|tta)|Yo(?:cto|etta))(?:mètre|watt|gramme|seconde|ampère|kelvin|mole|cand[eé]la|hertz|henry|newton|pascal|joule|coulomb|volt|ohm|farad|tesla|w[eé]ber|radian|stéradian|lumen|lux|becquerel|gray|sievert|siemens|katal)s?$ @:B ~(?:Exa|P[ée]ta|Téra|Giga|Méga|Kilo|Hecto|Déc[ai]|Centi|Milli|Micro|Nano|Pico|Femto|Atto|Ze(?:pto|tta)|Yo(?:cto|etta))(?:mètre|watt|gramme|seconde|ampère|kelvin|mole|cand[eé]la|hertz|henry|newton|pascal|joule|coulomb|volt|ohm|farad|tesla|w[eé]ber|radian|stéradian|lumen|lux|becquerel|gray|sievert|siemens|katal)s?$ - <<- /maj/ -2>> =\2.lower() # Pas de majuscule sur les unités de mesure.|https://fr.wikipedia.org/wiki/Unit%C3%A9_de_mesure + <<- /maj/ not \2.isupper() -2:>> =\2.lower() # Pas de majuscule sur les unités de mesure.|https://fr.wikipedia.org/wiki/Unit%C3%A9_de_mesure TEST: J’en veux 3 {{Mètres}}. TEST: Elle en prendra vingt {{Grammes}}.