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

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,478 @@
1
+ // Java: org.languagetool.language.French (rule lists, rule match filters and speller rules follow in F17/F16)
2
+ import { ArrayIndexOutOfBoundsException, IndexOutOfBoundsException, NullPointerException, RuntimeException, Throwable } from '@valueerror/ltjs-core/src/lib/java/errors.js';
3
+ import { Objects } from '@valueerror/ltjs-core/src/lib/java/Objects.js';
4
+ import { Pattern } from '@valueerror/ltjs-core/src/lib/java/regex/index.js';
5
+ import { javaSplit, javaTrim, javaReplaceAll, equalsIgnoreCase, toLowerCase, replaceChar } from '@valueerror/ltjs-core/src/lib/java/strings.js';
6
+ import { JavaHashMap } from '@valueerror/ltjs-core/src/lib/java/collections/JavaHashMap.js';
7
+ import { Languages } from '@valueerror/ltjs-core/src/core/Languages.js';
8
+ import { SRXSentenceTokenizer } from '@valueerror/ltjs-core/src/core/text/tokenizers/SRXSentenceTokenizer.js';
9
+ import { LanguageWithModel } from '@valueerror/ltjs-core/src/core/LanguageWithModel.js';
10
+ import { LanguageMaintainedState } from '@valueerror/ltjs-core/src/core/LanguageMaintainedState.js';
11
+ import { DOMINIQUE_PELLE } from '@valueerror/ltjs-core/src/core/language/Contributors.js';
12
+ import { createComponent, notPortedYet, sharedComponent } from '@valueerror/ltjs-core/src/core/language/components.js';
13
+ import { registerClass } from '@valueerror/ltjs-core/src/core/resources/ClassBroker.js';
14
+ import { RuleMatch } from '@valueerror/ltjs-core/src/core/rules/model/RuleMatch.js';
15
+ import { ITSIssueType } from '@valueerror/ltjs-core/src/core/rules/model/ITSIssueType.js';
16
+ import { Tag } from '@valueerror/ltjs-core/src/core/rules/model/Tag.js';
17
+ import { Categories } from '@valueerror/ltjs-core/src/core/rules/model/Category.js';
18
+ import { getMessageBundleForLanguage } from '@valueerror/ltjs-core/src/core/resources/ResourceBundleTools.js';
19
+ import { CommaWhitespaceRule } from '@valueerror/ltjs-core/src/core/rules/CommaWhitespaceRule.js';
20
+ import { DoublePunctuationRule } from '@valueerror/ltjs-core/src/core/rules/DoublePunctuationRule.js';
21
+ import { GenericUnpairedBracketsRule } from '@valueerror/ltjs-core/src/core/rules/GenericUnpairedBracketsRule.js';
22
+ import { UppercaseSentenceStartRule } from '@valueerror/ltjs-core/src/core/rules/UppercaseSentenceStartRule.js';
23
+ import { MultipleWhitespaceRule } from '@valueerror/ltjs-core/src/core/rules/MultipleWhitespaceRule.js';
24
+ import { SentenceWhitespaceRule } from '@valueerror/ltjs-core/src/core/rules/SentenceWhitespaceRule.js';
25
+ import { LongSentenceRule } from '@valueerror/ltjs-core/src/core/rules/LongSentenceRule.js';
26
+ import { LongParagraphRule } from '@valueerror/ltjs-core/src/core/rules/LongParagraphRule.js';
27
+ import { MorfologikFrenchSpellerRule } from '../rules/MorfologikFrenchSpellerRule.js';
28
+ import { CompoundRule } from '../rules/CompoundRule.js';
29
+ import { QuestionWhitespaceStrictRule } from '../rules/QuestionWhitespaceStrictRule.js';
30
+ import { QuestionWhitespaceRule } from '../rules/QuestionWhitespaceRule.js';
31
+ import { SimpleReplaceRule } from '../rules/SimpleReplaceRule.js';
32
+ import { FrenchRepeatedWordsRule } from '../rules/FrenchRepeatedWordsRule.js';
33
+ import { ID2PRIO_ENTRIES } from './id2prioFrench.js';
34
+
35
+ const TRAILING_WS = '\\s+$';
36
+
37
+ // Java: currentMatch.getSentence().getText() (helpful NPE when the sentence is null)
38
+ function sentenceText(m) {
39
+ if (m.getSentence() === null) throw new NullPointerException('Cannot invoke "org.languagetool.AnalyzedSentence.getText()" because the return value of "org.languagetool.rules.RuleMatch.getSentence()" is null');
40
+ return m.getSentence().getText();
41
+ }
42
+
43
+ // Java: match.getSuggestedReplacements().get(0)
44
+ function firstSuggestion(m) {
45
+ const l = m.getSuggestedReplacements();
46
+ if (l.length === 0) throw new IndexOutOfBoundsException('Index 0 out of bounds for length 0');
47
+ return l[0];
48
+ }
49
+
50
+ const BEFORE_APOS = '([cjnmtsldCJNMTSLD]|qu|jusqu|lorsqu|puisqu|quoiqu|Qu|Jusqu|Lorsqu|Puisqu|Quoiqu|QU|JUSQU|LORSQU|PUISQU|QUOIQU)';
51
+ const BEFORE_APOS_PATTERN_1 = Pattern.compile(`(\\b${BEFORE_APOS})'`);
52
+ const BEFORE_APOS_PATTERN_2 = Pattern.compile(`(\\b${BEFORE_APOS})’"`);
53
+ const BEFORE_APOS_PATTERN_3 = Pattern.compile(`(\\b${BEFORE_APOS})’'`);
54
+
55
+ const TYPOGRAPHY_PATTERN_1 = Pattern.compile(' ;');
56
+ const TYPOGRAPHY_PATTERN_2 = Pattern.compile(' !');
57
+ const TYPOGRAPHY_PATTERN_3 = Pattern.compile(' \\?');
58
+ const TYPOGRAPHY_PATTERN_4 = Pattern.compile(';');
59
+ const TYPOGRAPHY_PATTERN_5 = Pattern.compile('!');
60
+ const TYPOGRAPHY_PATTERN_6 = Pattern.compile('\\?');
61
+ const TYPOGRAPHY_PATTERN_7 = Pattern.compile(':');
62
+ const TYPOGRAPHY_PATTERN_8 = Pattern.compile('»');
63
+ const TYPOGRAPHY_PATTERN_9 = Pattern.compile('«');
64
+ const TYPOGRAPHY_PATTERN_10 = Pattern.compile('  ');
65
+ const TYPOGRAPHY_PATTERN_11 = Pattern.compile('  ');
66
+ const TYPOGRAPHY_PATTERN_12 = Pattern.compile(' ');
67
+ const TYPOGRAPHY_PATTERN_13 = Pattern.compile('  ');
68
+ const TYPOGRAPHY_PATTERN_14 = Pattern.compile('  ');
69
+ const TYPOGRAPHY_PATTERN_15 = Pattern.compile('  ');
70
+ const TYPOGRAPHY_PATTERN_16 = Pattern.compile('  ');
71
+
72
+ const FRENCH_SHORT_CODE = 'fr';
73
+
74
+ let instantiationTrace = null; // Java: French#instantiationTrace
75
+
76
+ const id2prio = new JavaHashMap(); // Java: French#id2prio
77
+ for (const [k, v] of ID2PRIO_ENTRIES) id2prio.put(k, v);
78
+
79
+ const spellerExceptions = ['Ho Chi Minh']; // Java: French#spellerExceptions
80
+
81
+ // Java: French
82
+ export class French extends LanguageWithModel {
83
+ static FQCN = 'org.languagetool.language.French';
84
+
85
+ // Java: French#French() / protected French(boolean) (fake constructor overload for subclasses)
86
+ constructor(fakeValue) {
87
+ super();
88
+ if (fakeValue === undefined) {
89
+ const trace = instantiationTrace;
90
+ if (trace !== null) {
91
+ throw new RuntimeException('Language was already instantiated, see the cause stacktrace below.', trace);
92
+ }
93
+ instantiationTrace = new Throwable();
94
+ }
95
+ }
96
+
97
+ // Java: French#createDefaultSentenceTokenizer()
98
+ createDefaultSentenceTokenizer() {
99
+ return new SRXSentenceTokenizer(this);
100
+ }
101
+
102
+ // Java: French#getName()
103
+ getName() {
104
+ return 'French';
105
+ }
106
+
107
+ // Java: French#getShortCode()
108
+ getShortCode() {
109
+ return FRENCH_SHORT_CODE;
110
+ }
111
+
112
+ // Java: French#getCountries()
113
+ getCountries() {
114
+ return ['FR', '', 'LU', 'MC', 'CM', 'CI', 'HT', 'ML', 'SN', 'CD', 'MA', 'RE'];
115
+ }
116
+
117
+ // Java: French#getDefaultLanguageVariant()
118
+ getDefaultLanguageVariant() {
119
+ return Languages.getLanguageForShortCode(FRENCH_SHORT_CODE);
120
+ }
121
+
122
+ // Java: French#createDefaultTagger()
123
+ createDefaultTagger() {
124
+ return sharedComponent('org.languagetool.tagging.fr.FrenchTagger');
125
+ }
126
+
127
+ // Java: French#createDefaultSynthesizer()
128
+ createDefaultSynthesizer() {
129
+ return sharedComponent('org.languagetool.synthesis.FrenchSynthesizer');
130
+ }
131
+
132
+ // Java: French#createDefaultWordTokenizer()
133
+ createDefaultWordTokenizer() {
134
+ return createComponent('org.languagetool.tokenizers.fr.FrenchWordTokenizer');
135
+ }
136
+
137
+ // Java: French#createDefaultDisambiguator()
138
+ createDefaultDisambiguator() {
139
+ return createComponent('org.languagetool.tagging.disambiguation.fr.FrenchHybridDisambiguator');
140
+ }
141
+
142
+ // Java: French#getMaintainers()
143
+ getMaintainers() {
144
+ return [DOMINIQUE_PELLE];
145
+ }
146
+
147
+ // Java: French#createDefaultSpellingRule(ResourceBundle)
148
+ createDefaultSpellingRule(messages) {
149
+ return createComponent('org.languagetool.rules.fr.MorfologikFrenchSpellerRule', messages, this, null, []);
150
+ }
151
+
152
+ // Java: French#getRelevantRules(ResourceBundle,UserConfig,Language,List)
153
+ getRelevantRules(messages, userConfig, motherTongue, altLanguages) {
154
+ return [
155
+ new CommaWhitespaceRule(messages, false),
156
+ new DoublePunctuationRule(messages),
157
+ new GenericUnpairedBracketsRule(messages, ['[', '(', '{'], [']', ')', '}']),
158
+ (userConfig === null || userConfig === undefined) && altLanguages.length === 0 ? this.getDefaultSpellingRule() : new MorfologikFrenchSpellerRule(messages, this, userConfig, altLanguages),
159
+ new UppercaseSentenceStartRule(messages, this),
160
+ new MultipleWhitespaceRule(messages, this),
161
+ new SentenceWhitespaceRule(messages),
162
+ new LongSentenceRule(messages, userConfig, 40),
163
+ new LongParagraphRule(messages, this, userConfig),
164
+ // specific to French:
165
+ new CompoundRule(messages, this, userConfig),
166
+ new QuestionWhitespaceStrictRule(messages, this),
167
+ new QuestionWhitespaceRule(messages, this),
168
+ new SimpleReplaceRule(messages, this),
169
+ new FrenchRepeatedWordsRule(messages),
170
+ ];
171
+ }
172
+
173
+ // Java: French#getRelevantRulesGlobalConfig(ResourceBundle,GlobalConfig,UserConfig,Language,List); no Grammalecte server is configured (DEV-001)
174
+ getRelevantRulesGlobalConfig() {
175
+ return [];
176
+ }
177
+
178
+ // Java: French#getRelevantLanguageModelRules(ResourceBundle,LanguageModel,UserConfig)
179
+ getRelevantLanguageModelRules(messages, languageModel) {
180
+ // FrenchConfusionProbabilityRule: the constructor dereferences the language model (Objects.requireNonNull)
181
+ if (languageModel === null || languageModel === undefined) return []; // DEV-026: Java NPE; no model, no model rules
182
+ throw notPortedYet('French#getRelevantLanguageModelRules (ngram rules, DEV-001)');
183
+ }
184
+
185
+ // Java: French#getOpeningDoubleQuote()
186
+ getOpeningDoubleQuote() {
187
+ return '«';
188
+ }
189
+
190
+ // Java: French#getClosingDoubleQuote()
191
+ getClosingDoubleQuote() {
192
+ return '»';
193
+ }
194
+
195
+ // Java: French#getOpeningSingleQuote()
196
+ getOpeningSingleQuote() {
197
+ return '‘';
198
+ }
199
+
200
+ // Java: French#getClosingSingleQuote()
201
+ getClosingSingleQuote() {
202
+ return '’';
203
+ }
204
+
205
+ // Java: French#isAdvancedTypographyEnabled()
206
+ isAdvancedTypographyEnabled() {
207
+ return true;
208
+ }
209
+
210
+ // Java: French#toAdvancedTypography(String)
211
+ toAdvancedTypography(input) {
212
+ let output = super.toAdvancedTypography(input);
213
+
214
+ // special cases: apostrophe + quotation marks
215
+ output = BEFORE_APOS_PATTERN_1.matcher(output).replaceAll('$1’');
216
+ output = BEFORE_APOS_PATTERN_2.matcher(output).replaceAll(`$1’${this.getOpeningDoubleQuote()}`);
217
+ output = BEFORE_APOS_PATTERN_3.matcher(output).replaceAll(`$1’${this.getOpeningSingleQuote()}`);
218
+
219
+ // non-breaking (thin) space
220
+ // according to https://fr.wikipedia.org/wiki/Espace_ins%C3%A9cable#En_France
221
+ output = TYPOGRAPHY_PATTERN_1.matcher(output).replaceAll(' ;');
222
+ output = TYPOGRAPHY_PATTERN_2.matcher(output).replaceAll(' !');
223
+ output = TYPOGRAPHY_PATTERN_3.matcher(output).replaceAll(' ?');
224
+ output = TYPOGRAPHY_PATTERN_4.matcher(output).replaceAll(' ;');
225
+ output = TYPOGRAPHY_PATTERN_5.matcher(output).replaceAll(' !');
226
+ output = TYPOGRAPHY_PATTERN_6.matcher(output).replaceAll(' ?');
227
+
228
+ output = TYPOGRAPHY_PATTERN_7.matcher(output).replaceAll(' :');
229
+ output = TYPOGRAPHY_PATTERN_8.matcher(output).replaceAll(' »');
230
+ output = TYPOGRAPHY_PATTERN_9.matcher(output).replaceAll('« ');
231
+
232
+ // remove duplicate spaces
233
+ output = TYPOGRAPHY_PATTERN_10.matcher(output).replaceAll(' ');
234
+ output = TYPOGRAPHY_PATTERN_11.matcher(output).replaceAll(' ');
235
+ output = TYPOGRAPHY_PATTERN_12.matcher(output).replaceAll(' ');
236
+ output = TYPOGRAPHY_PATTERN_13.matcher(output).replaceAll(' ');
237
+ output = TYPOGRAPHY_PATTERN_14.matcher(output).replaceAll(' ');
238
+ output = TYPOGRAPHY_PATTERN_15.matcher(output).replaceAll(' ');
239
+ output = TYPOGRAPHY_PATTERN_16.matcher(output).replaceAll(' ');
240
+
241
+ return output;
242
+ }
243
+
244
+ // Java: French#getMaintainedState()
245
+ getMaintainedState() {
246
+ return LanguageMaintainedState.ActivelyMaintained;
247
+ }
248
+
249
+ // Java: French#getPriorityMap()
250
+ getPriorityMap() {
251
+ return id2prio;
252
+ }
253
+
254
+ // Java: French#getPriorityForId(String)
255
+ getPriorityForId(id) {
256
+ const prio = id2prio.get(id);
257
+ if (prio !== null) {
258
+ return prio;
259
+ }
260
+ if (id.startsWith('FR_COMPOUNDS')) {
261
+ return 500;
262
+ }
263
+ if (id === 'CAT_TYPOGRAPHIE') {
264
+ return 20; // greater than PRONSUJ_NONVERBE or agreement rules
265
+ }
266
+ if (id === 'CAT_TOURS_CRITIQUES') {
267
+ return 20;
268
+ }
269
+ if (id === 'CAT_HOMONYMES_PARONYMES') {
270
+ return 20;
271
+ }
272
+ if (id === 'SON') {
273
+ return -5; // less than ETRE_VPPA_OU_ADJ
274
+ }
275
+ if (id.startsWith('CAR')) {
276
+ return -50; // lesser than grammar rules
277
+ }
278
+ if (id === 'CONFUSION_RULE_PREMIUM') {
279
+ return -50; // lesser than PRONSUJ_NONVERBE
280
+ }
281
+ if (id.startsWith('FR_MULTITOKEN_SPELLING_')) {
282
+ return -90;
283
+ }
284
+ if (id.startsWith('FR_SIMPLE_REPLACE')) {
285
+ return 150;
286
+ }
287
+ if (id.startsWith('grammalecte_')) {
288
+ return -150;
289
+ }
290
+
291
+ if (id.startsWith('AI_FR_HYDRA_LEO')) { // prefer more specific rules (also speller)
292
+ return -101;
293
+ }
294
+
295
+ if (id.startsWith('AI_FR_GGEC_REPLACEMENT_ORTHOGRAPHY')) { // prefer more specific rules (also speller)
296
+ return -101;
297
+ }
298
+ return super.getPriorityForId(id);
299
+ }
300
+
301
+ // Java: French#hasMinMatchesRules()
302
+ hasMinMatchesRules() {
303
+ return true;
304
+ }
305
+
306
+ // Java: French#filterRuleMatches(List,AnnotatedText,Set)
307
+ filterRuleMatches(ruleMatches, text, enabledRules) {
308
+ const resultMatches = [];
309
+ let previousMatch = null;
310
+ for (let i = 0; i < ruleMatches.length; i++) {
311
+ const currentMatch = this.adjustFrenchRuleMatch(ruleMatches[i], enabledRules);
312
+ const suggestions = currentMatch.getSuggestedReplacements();
313
+ // ignore adding punctuation at the sentence end
314
+ if (suggestions.length === 1 && currentMatch.getRule().getId().startsWith('AI_FR_GGEC')) {
315
+ const suggestion = suggestions[0];
316
+ if (currentMatch.getRule().getId() === 'AI_FR_GGEC_MISSING_PUNCTUATION_PERIOD' && suggestion.endsWith('.')) {
317
+ if (javaReplaceAll(sentenceText(currentMatch), TRAILING_WS, '').endsWith(suggestion.substring(0, suggestion.length - 1))) {
318
+ continue;
319
+ }
320
+ }
321
+ }
322
+ if (previousMatch !== null && previousMatch.getRule().getId().startsWith('AI_FR_GGEC')
323
+ && currentMatch.getRule().getId().startsWith('AI_FR_GGEC')) {
324
+ if (previousMatch.getToPos() > currentMatch.getFromPos()) {
325
+ continue; // Skip overlapping matches
326
+ }
327
+ // Check if matches are adjacent and share the same 'picky' status
328
+ if ((previousMatch.getToPos() === currentMatch.getFromPos() || previousMatch.getToPos() + 1 === currentMatch.getFromPos())
329
+ && (previousMatch.getRule().getTags().includes(Tag.picky) === currentMatch.getRule().getTags().includes(Tag.picky))) {
330
+ // Merge if they have the same ITSIssueType
331
+ if (previousMatch.getRule().getLocQualityIssueType() === currentMatch.getRule().getLocQualityIssueType()) {
332
+ const mergedMatch = new RuleMatch(this.mergeMatches(previousMatch, currentMatch));
333
+ previousMatch = mergedMatch;
334
+ continue;
335
+ }
336
+ // If matches have different ITSIssueTypes but neither is a style match, merge them
337
+ if (previousMatch.getRule().getLocQualityIssueType() !== currentMatch.getRule().getLocQualityIssueType()
338
+ && previousMatch.getRule().getLocQualityIssueType() !== ITSIssueType.Style && currentMatch.getRule().getLocQualityIssueType() !== ITSIssueType.Style) {
339
+ const mergedMatch = new RuleMatch(this.mergeMatches(previousMatch, currentMatch));
340
+ previousMatch = mergedMatch;
341
+ continue;
342
+ }
343
+ }
344
+ // If no merge happened, add the previous match to results
345
+ resultMatches.push(previousMatch);
346
+ previousMatch = currentMatch; // Move to next match
347
+ } else {
348
+ // Ensure current match becomes previous if no merging criteria are met
349
+ if (previousMatch !== null) {
350
+ resultMatches.push(previousMatch);
351
+ }
352
+ previousMatch = currentMatch;
353
+ }
354
+ }
355
+ // Add the last processed match if it exists and hasn't been added yet
356
+ if (previousMatch !== null) {
357
+ resultMatches.push(previousMatch);
358
+ }
359
+ return resultMatches;
360
+ }
361
+
362
+ // Java: French#mergeMatches(RuleMatch,RuleMatch)
363
+ mergeMatches(match1, match2) {
364
+ // Calculate separator based on position
365
+ let separator = '';
366
+ if (match1.getToPos() + 1 === match2.getFromPos()) {
367
+ separator = ' ';
368
+ }
369
+ // Merge original error strings and suggested replacements
370
+ const newErrorStr = match1.getOriginalErrorStr() + separator + match2.getOriginalErrorStr();
371
+ const newReplacement = firstSuggestion(match1) + separator + firstSuggestion(match2);
372
+
373
+ // Create a new merged RuleMatch object
374
+ const mergedMatch = new RuleMatch(match1.getRule(), match1.getSentence(), match1.getFromPos(), match2.getToPos(),
375
+ 'Il pourrait y avoir un problème ici.', 'Erreur potentielle');
376
+ mergedMatch.setOriginalErrorStr(newErrorStr);
377
+ mergedMatch.setSuggestedReplacement(newReplacement);
378
+
379
+ // Set ID based on issue type
380
+ let newId = 'AI_FR_MERGED_MATCH';
381
+ if (match1.getRule().getLocQualityIssueType().equals(ITSIssueType.Style)
382
+ && match2.getRule().getLocQualityIssueType().equals(ITSIssueType.Style)) {
383
+ newId += '_STYLE';
384
+ }
385
+ if (match1.getRule().getTags().includes(Tag.picky) && match2.getRule().getTags().includes(Tag.picky)) {
386
+ newId += '_PICKY';
387
+ }
388
+ mergedMatch.setSpecificRuleId(newId);
389
+
390
+ // Set ITSIssueType to Grammar unless both are Style
391
+ if (!match1.getRule().getLocQualityIssueType().equals(match2.getRule().getLocQualityIssueType())) {
392
+ mergedMatch.getRule().setLocQualityIssueType(ITSIssueType.Grammar);
393
+ } else if (match1.getRule().getLocQualityIssueType() === ITSIssueType.Style) {
394
+ mergedMatch.getRule().setLocQualityIssueType(ITSIssueType.Style);
395
+ }
396
+ return mergedMatch;
397
+ }
398
+
399
+ // Java: French#prepareLineForSpeller(String)
400
+ prepareLineForSpeller(line) {
401
+ const parts = javaSplit(line, '#');
402
+ if (parts.length === 0) {
403
+ return [line];
404
+ }
405
+ const formTag = javaSplit(parts[0], '[\t;]');
406
+ if (formTag.length === 0) throw new ArrayIndexOutOfBoundsException('Index 0 out of bounds for length 0');
407
+ const form = javaTrim(formTag[0]);
408
+ if (spellerExceptions.includes(form)) {
409
+ return [''];
410
+ }
411
+ if (formTag.length > 1) {
412
+ const tag = javaTrim(formTag[1]);
413
+ if (tag.startsWith('Z') || tag.startsWith('N') || tag === 'A') {
414
+ return [form];
415
+ }
416
+ return [''];
417
+ }
418
+ return [line];
419
+ }
420
+
421
+ // Java: French#getMultitokenSpeller()
422
+ getMultitokenSpeller() {
423
+ return sharedComponent('org.languagetool.rules.fr.FrenchMultitokenSpeller');
424
+ }
425
+
426
+ // Java: French#adjustFrenchRuleMatch(RuleMatch,Set)
427
+ adjustFrenchRuleMatch(rm, enabledRules) {
428
+ rm.setOriginalErrorStr();
429
+ const errorStr = rm.getOriginalErrorStr();
430
+ const suggestions = rm.getSuggestedReplacements();
431
+ if (suggestions.length === 1 && rm.getRule().getId().startsWith('AI_FR_GGEC')) {
432
+ const suggestion = suggestions[0];
433
+ // the suggestion only changes the casing
434
+ if (equalsIgnoreCase(suggestion, errorStr)) {
435
+ rm.setMessage('Un usage différent des majuscules et des minuscules est recommandé.');
436
+ rm.setShortMessage('Majuscules et minuscules');
437
+ rm.getRule().setLocQualityIssueType(ITSIssueType.Typographical);
438
+ rm.getRule().setCategory(Categories.CASING.getCategory(getMessageBundleForLanguage(this)));
439
+ rm.setSpecificRuleId(rm.getRule().getId().replaceAll('ORTHOGRAPHY', 'CASING'));
440
+ }
441
+ }
442
+ if (suggestions.length === 1 && rm.getRule().getId().startsWith('AI_FR_GGEC')
443
+ && rm.getRule().getId().includes('MISSING_PRONOUN_LAPOSTROPHE')) {
444
+ if (errorStr === 'on' && suggestions[0] === 'l\'on' && toLowerCase(sentenceText(rm)).includes('si on')) {
445
+ rm.setSpecificRuleId('AI_FR_GGEC_SI_LON');
446
+ rm.getRule().setTags([Tag.picky]);
447
+ }
448
+ }
449
+ if (rm.getRule().getId().startsWith('AI_FR_GGEC') && rm.getRule().getId().includes('REPLACEMENT_PUNCTUATION_QUOTE')) {
450
+ rm.setSpecificRuleId('AI_FR_GGEC_QUOTES');
451
+ rm.getRule().setTags([Tag.picky]);
452
+ rm.getRule().setLocQualityIssueType(ITSIssueType.Typographical);
453
+ }
454
+ // if the typographical apostrophe rule is enabled, use the typographical apostrophe in suggestons
455
+ if (enabledRules !== null && enabledRules !== undefined && enabledRules.has('APOS_TYP')) {
456
+ const newReplacements = [];
457
+ for (let s of rm.getSuggestedReplacements()) {
458
+ if (s.length > 1) {
459
+ s = replaceChar(s, 0x27, 0x2019);
460
+ }
461
+ newReplacements.push(s);
462
+ }
463
+ rm.setSuggestedReplacements(newReplacements);
464
+ }
465
+ return rm;
466
+ }
467
+
468
+ // Java: French#getInstance()
469
+ static getInstance() {
470
+ const language = Objects.requireNonNull(Languages.getLanguageForShortCode(FRENCH_SHORT_CODE));
471
+ if (language instanceof French) { // cannot use French here as in premium FRENCH_SHORT_CODE returns FrenchPremium
472
+ return language;
473
+ }
474
+ throw new RuntimeException(`French(Premium) language expected, got ${language}`);
475
+ }
476
+ }
477
+
478
+ registerClass(French.FQCN, French);
@@ -0,0 +1,38 @@
1
+ // Java: org.languagetool.language.SwissFrench
2
+ import { RuntimeException, Throwable } from '@valueerror/ltjs-core/src/lib/java/errors.js';
3
+ import { registerClass } from '@valueerror/ltjs-core/src/core/resources/ClassBroker.js';
4
+ import { French } from './French.js';
5
+
6
+ let instantiationTrace = null; // Java: SwissFrench#instantiationTrace
7
+
8
+ // Java: SwissFrench
9
+ export class SwissFrench extends French {
10
+ static FQCN = 'org.languagetool.language.SwissFrench';
11
+
12
+ // Java: SwissFrench#SwissFrench()
13
+ constructor() {
14
+ super(true);
15
+ const trace = instantiationTrace;
16
+ if (trace !== null) {
17
+ throw new RuntimeException('Language was already instantiated, see the cause stacktrace below.', trace);
18
+ }
19
+ instantiationTrace = new Throwable();
20
+ }
21
+
22
+ // Java: SwissFrench#getName()
23
+ getName() {
24
+ return 'French (Switzerland)';
25
+ }
26
+
27
+ // Java: SwissFrench#getCountries()
28
+ getCountries() {
29
+ return ['CH'];
30
+ }
31
+
32
+ // Java: SwissFrench#getDefaultDisabledRulesForVariant()
33
+ getDefaultDisabledRulesForVariant() {
34
+ return ['DOUBLER_UNE_CLASSE'];
35
+ }
36
+ }
37
+
38
+ registerClass(SwissFrench.FQCN, SwissFrench);
@@ -0,0 +1,102 @@
1
+ // Java: French#id2prio static initializer (put order; later duplicates overwrite)
2
+ export const ID2PRIO_ENTRIES = [
3
+ ["AGREEMENT_EXCEPTIONS", 100],
4
+ ["EXPRESSIONS_VU", 100],
5
+ ["SA_CA_SE", 100],
6
+ ["SIL_VOUS_PLAIT", 100],
7
+ ["QUASI_NOM", 100],
8
+ ["MA", 100],
9
+ ["SON_SONT", 100],
10
+ ["JE_TES", 100],
11
+ ["A_INFINITIF", 100],
12
+ ["ON_ONT", 100],
13
+ ["LEURS_LEUR", 100],
14
+ ["DU_DU", 100],
15
+ ["ACCORD_CHAQUE", 100],
16
+ ["J_N2", 100],
17
+ ["CEST_A_DIRE", 100],
18
+ ["FAIRE_VPPA", 100],
19
+ ["D_N_E_OU_E", 100],
20
+ ["GENS_ACCORD", 100],
21
+ ["VIRGULE_EXPRESSIONS_FIGEES", 100],
22
+ ["TRAIT_UNION", 100],
23
+ ["PLURIEL_AL2", 100],
24
+ ["FR_SPLIT_WORDS_HYPHEN", 100],
25
+ ["PAS_DE_TRAIT_UNION", 50],
26
+ ["SOCIOCULTUREL", 40],
27
+ ["A_VERBE_INFINITIF", 20],
28
+ ["DE_OU_DES", 20],
29
+ ["EMPLOI_EMPLOIE", 20],
30
+ ["VOIR_VOIRE", 20],
31
+ ["D_VPPA", 20],
32
+ ["EST_CE_QUE", 20],
33
+ ["CONFUSION_PARLEZ_PARLER", 10],
34
+ ["AGREEMENT_TOUT_LE", 10],
35
+ ["ESPACE_UNITES", 10],
36
+ ["BYTES", 10],
37
+ ["Y_A", 10],
38
+ ["COTE", 10],
39
+ ["PEUTETRE", 10],
40
+ ["A_A_ACCENT", 10],
41
+ ["A_ACCENT_A", 10],
42
+ ["A_A_ACCENT2", 10],
43
+ ["A_ACCENT", 10],
44
+ ["JE_M_APPEL", 10],
45
+ ["ACCORD_R_PERS_VERBE", 10],
46
+ ["JE_SUI", 10],
47
+ ["R_VAVOIR_VINF", 10],
48
+ ["AN_EN", 10],
49
+ ["APOS_M", 10],
50
+ ["ACCORD_PLURIEL_ORDINAUX", 10],
51
+ ["SUJET_AUXILIAIRE", 10],
52
+ ["ADJ_ADJ_SENT_END", 10],
53
+ ["OU_PAS", 10],
54
+ ["PLACE_DE_LA_VIRGULE", 10],
55
+ ["SE_CE", -10],
56
+ ["PAS_DE_SOUCIS", 10],
57
+ ["J_N", -10],
58
+ ["TE_NV", -20],
59
+ ["TE_NV2", -10],
60
+ ["INTERROGATIVE_DIRECTE", -10],
61
+ ["V_J_A_R", -10],
62
+ ["TRES_TRES_ADJ", -10],
63
+ ["IMP_PRON", -10],
64
+ ["TOO_LONG_PARAGRAPH", -15],
65
+ ["PREP_VERBECONJUGUE", -20],
66
+ ["LA_LA2", -20],
67
+ ["FRENCH_WORD_REPEAT_RULE", -20],
68
+ ["PAS_DE_VERBE_APRES_POSSESSIF_DEMONSTRATIF", -20],
69
+ ["VIRGULE_VERBE", -20],
70
+ ["VERBES_FAMILIERS", -25],
71
+ ["VERB_PRONOUN", -50],
72
+ ["IL_VERBE", -50],
73
+ ["A_LE", -50],
74
+ ["ILS_VERBE", -50],
75
+ ["AGREEMENT_POSTPONED_ADJ", -50],
76
+ ["MULTI_ADJ", -50],
77
+ ["PARENTHESES", -50],
78
+ ["REP_ESSENTIEL", -50],
79
+ ["CONFUSION_AL_LA", -50],
80
+ ["LE_COVID", -60],
81
+ ["FR_SPELLING_RULE", -100],
82
+ ["VIRG_INF", -100],
83
+ ["ET_SENT_START", -151],
84
+ ["MAIS_SENT_START", -151],
85
+ ["EN_CE_QUI_CONCERNE", -152],
86
+ ["EN_MEME_TEMPS", -152],
87
+ ["ET_AUSSI", -152],
88
+ ["MAIS_AUSSI", -152],
89
+ ["ELISION", -200],
90
+ ["POINT", -200],
91
+ ["REPETITIONS_STYLE", -250],
92
+ ["POINTS_SUSPENSIONS_SPACE", -250],
93
+ ["UPPERCASE_SENTENCE_START", -300],
94
+ ["FRENCH_WHITESPACE_STRICT", -350],
95
+ ["TOUT_MAJUSCULES", -400],
96
+ ["VIRG_NON_TROUVEE", -400],
97
+ ["POINTS_2", -400],
98
+ ["MOTS_INCOMP", -400],
99
+ ["FRENCH_WHITESPACE", -400],
100
+ ["MOT_TRAIT_MOT", -400],
101
+ ["FRENCH_WORD_REPEAT_BEGINNING_RULE", -350],
102
+ ];
@@ -0,0 +1,12 @@
1
+ // org.languagetool.rules.fr.AdvancedSynthesizerFilter
2
+ import { registerClass } from '@valueerror/ltjs-core/src/core/resources/ClassBroker.js';
3
+ import { AbstractAdvancedSynthesizerFilter } from '@valueerror/ltjs-core/src/core/rules/AbstractAdvancedSynthesizerFilter.js';
4
+
5
+ // Java: AdvancedSynthesizerFilter
6
+ export class AdvancedSynthesizerFilter extends AbstractAdvancedSynthesizerFilter {
7
+ static FQCN = 'org.languagetool.rules.fr.AdvancedSynthesizerFilter';
8
+ static JAVA_ABSTRACT = false;
9
+ static JAVA_CONSTRUCTORS = [{ params: [], text: 'public org.languagetool.rules.fr.AdvancedSynthesizerFilter()' }];
10
+ }
11
+
12
+ registerClass(AdvancedSynthesizerFilter.FQCN, AdvancedSynthesizerFilter);
@@ -0,0 +1,47 @@
1
+ // org.languagetool.rules.fr.CompoundRule
2
+ import { AbstractCompoundRule } from '@valueerror/ltjs-core/src/core/rules/AbstractCompoundRule.js';
3
+ import { CompoundRuleData } from '@valueerror/ltjs-core/src/core/rules/CompoundRuleData.js';
4
+ import { Example } from '@valueerror/ltjs-core/src/core/rules/model/Examples.js';
5
+ import { FrenchTagger } from '../tagging/FrenchTagger.js';
6
+
7
+ let compoundData = null; // Java: static volatile compoundData
8
+
9
+ // Java: CompoundRule
10
+ export class CompoundRule extends AbstractCompoundRule {
11
+ static FQCN = 'org.languagetool.rules.fr.CompoundRule';
12
+
13
+ // Java: CompoundRule(ResourceBundle,Language,UserConfig)
14
+ constructor(messages, lang, userConfig) {
15
+ super(messages, lang, userConfig,
16
+ 'Écrivez avec un trait d’union.',
17
+ 'Écrivez avec un mot seul sans espace ni trait d’union.',
18
+ 'Écrivez avec un mot seul ou avec trait d’union.',
19
+ 'Erreur de trait d’union');
20
+ this.addExamplePair(Example.wrong('Le <marker>Haut Rhin</marker>.'),
21
+ Example.fixed('Le <marker>Haut-Rhin</marker>.'));
22
+ super.useSubRuleSpecificIds();
23
+ }
24
+
25
+ // Java: CompoundRule#getId()
26
+ getId() {
27
+ return 'FR_COMPOUNDS';
28
+ }
29
+
30
+ // Java: CompoundRule#getDescription()
31
+ getDescription() {
32
+ return 'Mots avec trait d’union : $match';
33
+ }
34
+
35
+ // Java: CompoundRule#getCompoundRuleData()
36
+ getCompoundRuleData() {
37
+ if (compoundData === null) {
38
+ compoundData = new CompoundRuleData('/fr/compounds.txt');
39
+ }
40
+ return compoundData;
41
+ }
42
+
43
+ // Java: CompoundRule#isMisspelled(String)
44
+ isMisspelled(word) {
45
+ return !FrenchTagger.INSTANCE.tag([word])[0].isTagged();
46
+ }
47
+ }