@valueerror/ltjs-lang-fr 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/LICENSE +232 -0
  2. package/NOTICE +9 -0
  3. package/README.md +25 -2
  4. package/index.js +24 -0
  5. package/licenses/LGPL-2.1.txt +504 -0
  6. package/licenses/french-pos-dict.pom.xml +115 -0
  7. package/licenses/resource_fr_README_lexique.txt +30 -0
  8. package/licenses/resource_fr_hunspell_README_fr.txt +73 -0
  9. package/package.json +60 -4
  10. package/resource-root.js +4 -0
  11. package/resources/META-INF/org/languagetool/language-module.properties +1 -0
  12. package/resources/org/languagetool/resource/fr/README_lexique.txt +30 -0
  13. package/resources/org/languagetool/resource/fr/added.txt +477 -0
  14. package/resources/org/languagetool/resource/fr/added_custom.txt +4 -0
  15. package/resources/org/languagetool/resource/fr/compounds.txt +1443 -0
  16. package/resources/org/languagetool/resource/fr/confusion_sets.txt +76 -0
  17. package/resources/org/languagetool/resource/fr/disambiguation.xml +11391 -0
  18. package/resources/org/languagetool/resource/fr/fr.sor +162 -0
  19. package/resources/org/languagetool/resource/fr/french.dict +0 -0
  20. package/resources/org/languagetool/resource/fr/french.info +20 -0
  21. package/resources/org/languagetool/resource/fr/french_synth.dict +0 -0
  22. package/resources/org/languagetool/resource/fr/french_synth.info +4 -0
  23. package/resources/org/languagetool/resource/fr/french_tags.txt +268 -0
  24. package/resources/org/languagetool/resource/fr/hunspell/README_fr.txt +73 -0
  25. package/resources/org/languagetool/resource/fr/hunspell/ignore.txt +1551 -0
  26. package/resources/org/languagetool/resource/fr/hunspell/prohibit.txt +3 -0
  27. package/resources/org/languagetool/resource/fr/hunspell/spelling.txt +34735 -0
  28. package/resources/org/languagetool/resource/fr/hunspell/spelling_custom.txt +1 -0
  29. package/resources/org/languagetool/resource/fr/hyphenated_words.txt +12864 -0
  30. package/resources/org/languagetool/resource/fr/multiwords.txt +4886 -0
  31. package/resources/org/languagetool/resource/fr/removed.txt +5 -0
  32. package/resources/org/languagetool/resource/fr/removed_custom.txt +4 -0
  33. package/resources/org/languagetool/rules/fr/grammar.xml +151570 -0
  34. package/resources/org/languagetool/rules/fr/remote-rule-filters.xml +820 -0
  35. package/resources/org/languagetool/rules/fr/replace.txt +39 -0
  36. package/resources/org/languagetool/rules/fr/replace_custom.txt +7 -0
  37. package/resources/org/languagetool/rules/fr/style.xml +22790 -0
  38. package/resources/org/languagetool/rules/fr/synonyms.txt +203 -0
  39. package/src/lang/fr/language/BelgianFrench.js +38 -0
  40. package/src/lang/fr/language/CanadianFrench.js +38 -0
  41. package/src/lang/fr/language/French.js +478 -0
  42. package/src/lang/fr/language/SwissFrench.js +38 -0
  43. package/src/lang/fr/language/id2prioFrench.js +102 -0
  44. package/src/lang/fr/rules/AdvancedSynthesizerFilter.js +12 -0
  45. package/src/lang/fr/rules/CompoundRule.js +47 -0
  46. package/src/lang/fr/rules/DMYDateCheckFilter.js +31 -0
  47. package/src/lang/fr/rules/DateCheckFilter.js +35 -0
  48. package/src/lang/fr/rules/DateFilterHelper.js +55 -0
  49. package/src/lang/fr/rules/FindSuggestionsFilter.js +80 -0
  50. package/src/lang/fr/rules/FrenchLazy.js +9 -0
  51. package/src/lang/fr/rules/FrenchMultitokenSpeller.js +15 -0
  52. package/src/lang/fr/rules/FrenchNumberInWordFilter.js +29 -0
  53. package/src/lang/fr/rules/FrenchPartialPosTagFilter.js +29 -0
  54. package/src/lang/fr/rules/FrenchRepeatedWordsRule.js +76 -0
  55. package/src/lang/fr/rules/FrenchSuppressMisspelledSuggestionsFilter.js +12 -0
  56. package/src/lang/fr/rules/InterrogativeVerbFilter.js +159 -0
  57. package/src/lang/fr/rules/MakeContractionsFilter.js +32 -0
  58. package/src/lang/fr/rules/MorfologikFrenchSpellerRule.js +262 -0
  59. package/src/lang/fr/rules/NewYearDateFilter.js +30 -0
  60. package/src/lang/fr/rules/PostponedAdjectiveConcordanceFilter.js +512 -0
  61. package/src/lang/fr/rules/QuestionWhitespaceRule.js +171 -0
  62. package/src/lang/fr/rules/QuestionWhitespaceStrictRule.js +38 -0
  63. package/src/lang/fr/rules/SimpleReplaceRule.js +63 -0
  64. package/src/lang/fr/rules/SuggestionsFilter.js +29 -0
  65. package/src/lang/fr/rules/WordWithDeterminerFilter.js +168 -0
  66. package/src/lang/fr/synthesis/FrenchSynthesizer.js +36 -0
  67. package/src/lang/fr/tagging/FrenchHybridDisambiguator.js +28 -0
  68. package/src/lang/fr/tagging/FrenchTagger.js +176 -0
  69. package/src/lang/fr/tokenizers/FrenchWordTokenizer.js +164 -0
@@ -0,0 +1,262 @@
1
+ // org.languagetool.rules.fr.MorfologikFrenchSpellerRule
2
+ import { MorfologikSpellerRule } from '@valueerror/ltjs-core/src/core/rules/spelling/morfologik/MorfologikSpellerRule.js';
3
+ import { SuggestedReplacement } from '@valueerror/ltjs-core/src/core/rules/model/SuggestedReplacement.js';
4
+ import { removeDiacritics, splitCamelCase, splitDigitsAtEnd } from '@valueerror/ltjs-core/src/core/text/StringTools.js';
5
+ import { registerComponent } from '@valueerror/ltjs-core/src/core/language/components.js';
6
+ import { FrenchTagger } from '../tagging/FrenchTagger.js';
7
+ import { Pattern } from '@valueerror/ltjs-core/src/lib/java/regex/index.js';
8
+ import { equalsIgnoreCase, javaSplit, toLowerCase } from '@valueerror/ltjs-core/src/lib/java/strings.js';
9
+
10
+ const SPELLING_FILE = '/fr/hunspell/spelling.txt';
11
+
12
+ const flags = Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE;
13
+ const TOKEN_AT_START = ['non', 'en', 'a', 'le', 'la', 'les', 'pour', 'de',
14
+ 'du', 'des', 'un', 'une', 'mon', 'ma', 'mes', 'ton', 'ta', 'tes', 'son', 'sa', 'ses', 'leur', 'leurs', 'ce', 'cet'];
15
+ const PREFIX_WITH_WHITESPACE = ['agro', 'anti', 'archi', 'auto', 'aéro',
16
+ 'cardio', 'co', 'cyber', 'demi', 'ex', 'extra', 'géo', 'hospitalo', 'hydro', 'hyper', 'hypo', 'infra', 'inter',
17
+ 'macro', 'mega', 'meta', 'mi', 'micro', 'mini', 'mono', 'multi', 'musculo', 'méga', 'méta', 'néo', 'omni', 'pan',
18
+ 'para', 'pluri', 'poly', 'post', 'prim', 'pro', 'proto', 'pré', 'pseudo', 'psycho', 'péri', 're', 'retro', 'ré',
19
+ 'semi', 'simili', 'socio', 'super', 'supra', 'sus', 'trans', 'tri', 'télé', 'ultra', 'uni', 'vice', 'éco'];
20
+ // grand, haut, nord, sud, sous, sur l|d|s|t
21
+ const exceptionsEgrave = ['burkinabè', 'koinè', 'épistémè'];
22
+ const APOSTROF_INICI_VERBS = Pattern.compile("^([lnts])(h?[aeiouàéèíòóú].*[^è])$", flags);
23
+ const APOSTROF_INICI_VERBS_M = Pattern.compile("^(m)(h?[aeiouàéèíòóú].*[^è])$", flags);
24
+ const APOSTROF_INICI_VERBS_C = Pattern.compile("^(c)([eiéèê].*)$", flags);
25
+ const APOSTROF_INICI_NOM_SING = Pattern.compile("^([ld])(h?[aeiouàéèíòóú]...+)$", flags);
26
+ const APOSTROF_INICI_NOM_PLURAL = Pattern.compile("^(d)(h?[aeiouàéèíòóú].+)$", flags);
27
+ const APOSTROF_INICI_VERBS_INF = Pattern.compile("^([lntsmd]|nous|vous)(h?[aeiouàéèíòóú].*[^è])$", flags);
28
+ const HYPHEN_ON = Pattern.compile("^([\\p{L}]+[^aeiou])[’']?(il|elle|ce|on)$", flags);
29
+ const HYPHEN_JE = Pattern.compile("^([\\p{L}]+[^e])[’']?(je)$", flags);
30
+ const HYPHEN_TU = Pattern.compile("^([\\p{L}]+)[’']?(tu)$", flags);
31
+ const HYPHEN_NOUS = Pattern.compile("^([\\p{L}]+)[’']?(nous)$", flags);
32
+ const HYPHEN_VOUS = Pattern.compile("^([\\p{L}]+)[’']?(vous)$", flags);
33
+ const HYPHEN_ILS = Pattern.compile("^([\\p{L}]+)[’']?(ils|elles)$", flags);
34
+ const VERB_INDSUBJ = Pattern.compile("V .*(ind|sub).*");
35
+ const VERB_IMP = Pattern.compile("V.* imp .*");
36
+ const VERB_INF = Pattern.compile("V.* inf");
37
+ const VERB_INDSUBJ_M = Pattern.compile("V .* [123] s|V .* [23] p");
38
+ const VERB_INDSUBJ_C = Pattern.compile("V .* 3 s");
39
+ const NOM_SING = Pattern.compile("[NJZ] .* (s|sp)|V .inf|V .*ppa.* s");
40
+ const NOM_PLURAL = Pattern.compile("[NJZ] .* (p|sp)|V .*ppa.* p");
41
+ const ANY_TAG = Pattern.compile("[NAZJPD].*");
42
+ const VERB_1S = Pattern.compile("V .*(ind).* 1 s");
43
+ const VERB_2S = Pattern.compile("V .*(ind).* 2 s");
44
+ const VERB_3S = Pattern.compile("V .*(ind).* 3 s");
45
+ const VERB_1P = Pattern.compile("V .*(ind).* 1 p");
46
+ const VERB_2P = Pattern.compile("V .*(ind).* 2 p");
47
+ const VERB_3P = Pattern.compile("V .*(ind).* 3 p");
48
+ const HYPHEN_OR_QUOTE = Pattern.compile("['-]");
49
+ const IMPERATIVE_HYPHEN = Pattern.compile(
50
+ "^([\\p{L}]+)[’']?(moi|toi|le|la|lui|nous|vous|les|leur|y|en)$", flags); //|vs|y
51
+ const SPLIT_DIGITS_AT_END = ['et', 'ou', 'de', 'en', 'à', 'aux', 'des'];
52
+ const DICT_FILE = '/fr/french.dict';
53
+
54
+ // Java: MorfologikFrenchSpellerRule
55
+ export class MorfologikFrenchSpellerRule extends MorfologikSpellerRule {
56
+ static FQCN = 'org.languagetool.rules.fr.MorfologikFrenchSpellerRule';
57
+
58
+ // Java: MorfologikFrenchSpellerRule(ResourceBundle,Language,UserConfig,List)
59
+ constructor(messages, language, userConfig, altLanguages) {
60
+ super(messages, language, userConfig, altLanguages);
61
+ this.setIgnoreTaggedWords();
62
+ }
63
+
64
+ // Java: MorfologikFrenchSpellerRule#getFileName()
65
+ getFileName() {
66
+ return DICT_FILE;
67
+ }
68
+
69
+ // Java: MorfologikFrenchSpellerRule#getSpellingFileName()
70
+ getSpellingFileName() {
71
+ return SPELLING_FILE;
72
+ }
73
+
74
+ // Java: MorfologikFrenchSpellerRule#getId()
75
+ getId() {
76
+ return 'FR_SPELLING_RULE'; // same name just for diffs
77
+ }
78
+
79
+ // Use this rule in LO/OO extension despite being a spelling rule
80
+ // Java: MorfologikFrenchSpellerRule#useInOffice()
81
+ useInOffice() {
82
+ return true;
83
+ }
84
+
85
+ // Java: MorfologikFrenchSpellerRule#orderSuggestions(List,String)
86
+ orderSuggestions(suggestions, word) {
87
+ // move some run-on-words suggestions to the top
88
+ const newSuggestions = [];
89
+ const wordWithouDiacriticsString = removeDiacritics(word);
90
+ for (let i = 0; i < suggestions.length; i++) {
91
+ const parts = javaSplit(toLowerCase(suggestions[i].getReplacement()), ' ');
92
+
93
+ // remove wrong split prefixes
94
+ if (parts.length === 2 && PREFIX_WITH_WHITESPACE.includes(parts[0])) {
95
+ continue;
96
+ }
97
+ if (parts[0].length === 1 && parts[0] !== 'a' && parts[0] !== 'à' && parts[0] !== 'y') {
98
+ continue;
99
+ }
100
+ // remove: informè V ind pres 1 s
101
+ if (toLowerCase(suggestions[i].getReplacement()).endsWith('è')
102
+ && !exceptionsEgrave.includes(toLowerCase(suggestions[i].getReplacement()))) {
103
+ continue;
104
+ }
105
+
106
+ // Don't change first suggestions if they match word without diacritics
107
+ let posNewSugg = 0;
108
+ while (newSuggestions.length > posNewSugg
109
+ && equalsIgnoreCase(removeDiacritics(newSuggestions[posNewSugg].getReplacement()), wordWithouDiacriticsString)) {
110
+ posNewSugg++;
111
+ }
112
+ // move some split words to first place
113
+ if (parts.length === 2 && TOKEN_AT_START.includes(parts[0]) && parts[1].length > 1) {
114
+ newSuggestions.splice(posNewSugg, 0, suggestions[i]);
115
+ continue;
116
+ }
117
+
118
+ const suggWithoutDiacritics = removeDiacritics(suggestions[i].getReplacement());
119
+ if (equalsIgnoreCase(wordWithouDiacriticsString, suggWithoutDiacritics)) {
120
+ newSuggestions.splice(posNewSugg, 0, suggestions[i]);
121
+ continue;
122
+ }
123
+
124
+ // move words with apostrophe or hyphen to second position
125
+ const cleanSuggestion = HYPHEN_OR_QUOTE.matcher(suggestions[i].getReplacement()).replaceAll('');
126
+ if (i > 1 && suggestions.length > 2 && equalsIgnoreCase(cleanSuggestion, word)) {
127
+ if (posNewSugg === 0) {
128
+ posNewSugg = 1;
129
+ }
130
+ newSuggestions.splice(posNewSugg, 0, suggestions[i]);
131
+ continue;
132
+ }
133
+ newSuggestions.push(suggestions[i]);
134
+ }
135
+ return newSuggestions;
136
+ }
137
+
138
+ // Java: MorfologikFrenchSpellerRule#getAdditionalTopSuggestions(List,String)
139
+ getAdditionalTopSuggestions(suggestions, word) {
140
+ const suggestionsList = suggestions.map((s) => s.getReplacement());
141
+ return SuggestedReplacement.convert(this.getAdditionalTopSuggestionsString(suggestionsList, word));
142
+ }
143
+
144
+ // Java: MorfologikFrenchSpellerRule#getAdditionalTopSuggestionsString(List,String)
145
+ getAdditionalTopSuggestionsString(suggestions, word) {
146
+ if (word === 'voulai') {
147
+ return ['voulais', 'voulait'];
148
+ } else if (equalsIgnoreCase(word, 'mm2')) {
149
+ return ['mm²'];
150
+ } else if (equalsIgnoreCase(word, 'cm2')) {
151
+ return ['cm²'];
152
+ } else if (equalsIgnoreCase(word, 'dm2')) {
153
+ return ['dm²'];
154
+ } else if (equalsIgnoreCase(word, 'm2')) {
155
+ return ['m²'];
156
+ } else if (equalsIgnoreCase(word, 'km2')) {
157
+ return ['km²'];
158
+ } else if (equalsIgnoreCase(word, 'mm3')) {
159
+ return ['mm³'];
160
+ } else if (equalsIgnoreCase(word, 'cm3')) {
161
+ return ['cm³'];
162
+ } else if (equalsIgnoreCase(word, 'dm3')) {
163
+ return ['dm³'];
164
+ } else if (equalsIgnoreCase(word, 'm3')) {
165
+ return ['m³'];
166
+ } else if (equalsIgnoreCase(word, 'km3')) {
167
+ return ['km³'];
168
+ }
169
+ let parts = splitCamelCase(word);
170
+ if (parts.length > 1 && parts[0].length > 1) {
171
+ let isNotMisspelled = true;
172
+ for (const part of parts) {
173
+ isNotMisspelled = !this.speller1.isMisspelled(part) && isNotMisspelled; // Java: isNotMisspelled &= ... (no short-circuit)
174
+ }
175
+ if (isNotMisspelled) {
176
+ return [parts.join(' ')];
177
+ }
178
+ }
179
+ parts = splitDigitsAtEnd(word);
180
+ if (parts.length > 1) {
181
+ if (FrenchTagger.INSTANCE.tag([parts[0]])[0].isTagged()
182
+ && (parts[0].length > 2 || SPLIT_DIGITS_AT_END.includes(toLowerCase(parts[0])))) {
183
+ return [parts.join(' ')];
184
+ }
185
+ }
186
+ const newSuggestions = [];
187
+ newSuggestions.push(...this.findSuggestion(word, APOSTROF_INICI_VERBS, VERB_INDSUBJ, 2, "'", true));
188
+ newSuggestions.push(...this.findSuggestion(word, APOSTROF_INICI_VERBS_M, VERB_INDSUBJ_M, 2, "'", true));
189
+ newSuggestions.push(...this.findSuggestion(word, APOSTROF_INICI_VERBS_C, VERB_INDSUBJ_C, 2, "'", true));
190
+ newSuggestions.push(...this.findSuggestion(word, APOSTROF_INICI_VERBS_INF, VERB_INF, 2, "'", true));
191
+ newSuggestions.push(...this.findSuggestion(word, APOSTROF_INICI_NOM_SING, NOM_SING, 2, "'", true));
192
+ newSuggestions.push(...this.findSuggestion(word, APOSTROF_INICI_NOM_PLURAL, NOM_PLURAL, 2, "'", true));
193
+ newSuggestions.push(...this.findSuggestion(word, IMPERATIVE_HYPHEN, VERB_IMP, 1, '-', true));
194
+
195
+ newSuggestions.push(...this.findSuggestion(word, HYPHEN_JE, VERB_1S, 1, '-', true));
196
+ newSuggestions.push(...this.findSuggestion(word, HYPHEN_TU, VERB_2S, 1, '-', true));
197
+ newSuggestions.push(...this.findSuggestion(word, HYPHEN_ON, VERB_3S, 1, '-', true));
198
+ newSuggestions.push(...this.findSuggestion(word, HYPHEN_NOUS, VERB_1P, 1, '-', true));
199
+ newSuggestions.push(...this.findSuggestion(word, HYPHEN_VOUS, VERB_2P, 1, '-', true));
200
+ newSuggestions.push(...this.findSuggestion(word, HYPHEN_ILS, VERB_3P, 1, '-', true));
201
+
202
+ if (newSuggestions.length !== 0) {
203
+ return newSuggestions;
204
+ }
205
+ return [];
206
+ }
207
+
208
+ // Java: MorfologikFrenchSpellerRule#findSuggestion(String,Pattern,Pattern,int,String,boolean)
209
+ findSuggestion(word, wordPattern, postagPattern, suggestionPosition, separator, recursive) {
210
+ const newSuggestions = [];
211
+ const matcher = wordPattern.matcher(word);
212
+ if (matcher.matches()) {
213
+ const newSuggestion = matcher.group(suggestionPosition);
214
+ const newatr = FrenchTagger.INSTANCE.tag([newSuggestion])[0];
215
+ if (this.matchPostagRegexp(newatr, postagPattern)) {
216
+ newSuggestions.push(matcher.group(1) + separator + matcher.group(2));
217
+ return newSuggestions;
218
+ }
219
+ if (recursive) {
220
+ const moreSugg = this.speller1.getSuggestions(newSuggestion);
221
+ if (moreSugg.length > 0) {
222
+ for (let i = 0; i < moreSugg.length; i++) {
223
+ let newWord;
224
+ if (suggestionPosition === 1) {
225
+ newWord = moreSugg[i] + matcher.group(2); // .toLowerCase()
226
+ } else {
227
+ newWord = matcher.group(1) + moreSugg[i];
228
+ }
229
+ const newSugg = this.findSuggestion(newWord, wordPattern, postagPattern, suggestionPosition, separator, false);
230
+ if (newSugg.length !== 0) {
231
+ newSuggestions.push(...newSugg);
232
+ }
233
+ if (i > 5) {
234
+ break;
235
+ }
236
+ }
237
+ }
238
+ }
239
+ }
240
+ if (newSuggestions.length !== 0) {
241
+ return newSuggestions;
242
+ }
243
+ return [];
244
+ }
245
+
246
+ // Match POS tag with regular expression
247
+ // Java: MorfologikFrenchSpellerRule#matchPostagRegexp(AnalyzedTokenReadings,Pattern)
248
+ matchPostagRegexp(aToken, pattern) {
249
+ for (const analyzedToken of aToken.getReadings()) {
250
+ let posTag = analyzedToken.getPOSTag();
251
+ if (posTag === null) {
252
+ posTag = 'UNKNOWN';
253
+ }
254
+ const m = pattern.matcher(posTag);
255
+ if (m.matches()) {
256
+ return true;
257
+ }
258
+ }
259
+ return false;
260
+ }
261
+ }
262
+ registerComponent(MorfologikFrenchSpellerRule.FQCN, (...args) => new MorfologikFrenchSpellerRule(...args));
@@ -0,0 +1,30 @@
1
+ // org.languagetool.rules.fr.NewYearDateFilter
2
+ import { registerClass } from '@valueerror/ltjs-core/src/core/resources/ClassBroker.js';
3
+ import { AbstractNewYearDateFilter } from '@valueerror/ltjs-core/src/core/rules/AbstractNewYearDateFilter.js';
4
+ import { DateFilterHelper } from './DateFilterHelper.js';
5
+
6
+ // Java: NewYearDateFilter
7
+ export class NewYearDateFilter extends AbstractNewYearDateFilter {
8
+ static FQCN = 'org.languagetool.rules.fr.NewYearDateFilter';
9
+ static JAVA_ABSTRACT = false;
10
+ static JAVA_CONSTRUCTORS = [{ params: [], text: 'public org.languagetool.rules.fr.NewYearDateFilter()' }];
11
+
12
+ dateFilterHelper = new DateFilterHelper();
13
+
14
+ // Java: NewYearDateFilter#getMonth(String)
15
+ getMonth(localizedMonth) {
16
+ return this.dateFilterHelper.getMonth(localizedMonth);
17
+ }
18
+
19
+ // Java: NewYearDateFilter#getCalendar()
20
+ getCalendar() {
21
+ return this.dateFilterHelper.getCalendar();
22
+ }
23
+
24
+ // Java: NewYearDateFilter#getDayOfWeek(Calendar)
25
+ getDayOfWeek(date) {
26
+ return this.dateFilterHelper.getDayOfWeek(date);
27
+ }
28
+ }
29
+
30
+ registerClass(NewYearDateFilter.FQCN, NewYearDateFilter);