73 |
ilm |
1 |
/*
|
|
|
2 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
|
|
|
3 |
*
|
|
|
4 |
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
|
|
|
5 |
*
|
|
|
6 |
* The contents of this file are subject to the terms of the GNU General Public License Version 3
|
|
|
7 |
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
|
|
|
8 |
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
|
|
|
9 |
* language governing permissions and limitations under the License.
|
|
|
10 |
*
|
|
|
11 |
* When distributing the software, include this License Header Notice in each file.
|
|
|
12 |
*/
|
|
|
13 |
|
|
|
14 |
package org.openconcerto.utils.i18n;
|
|
|
15 |
|
|
|
16 |
import java.text.Normalizer;
|
|
|
17 |
import java.text.Normalizer.Form;
|
|
|
18 |
import java.util.Arrays;
|
|
|
19 |
import java.util.Collection;
|
|
|
20 |
import java.util.Locale;
|
|
|
21 |
import java.util.regex.Matcher;
|
|
|
22 |
import java.util.regex.Pattern;
|
|
|
23 |
|
|
|
24 |
import net.jcip.annotations.Immutable;
|
|
|
25 |
|
|
|
26 |
@Immutable
|
|
|
27 |
public class Grammar_fr extends Grammar {
|
|
|
28 |
|
|
|
29 |
static private final Grammar_fr INSTANCE = new Grammar_fr();
|
|
|
30 |
|
|
|
31 |
public static Grammar_fr getInstance() {
|
|
|
32 |
return INSTANCE;
|
|
|
33 |
}
|
|
|
34 |
|
|
|
35 |
private Grammar_fr() {
|
|
|
36 |
this(Locale.FRENCH);
|
|
|
37 |
}
|
|
|
38 |
|
|
|
39 |
protected Grammar_fr(final Locale l) {
|
|
|
40 |
super(l);
|
|
|
41 |
}
|
|
|
42 |
|
|
|
43 |
@Override
|
|
|
44 |
protected Collection<? extends VariantKey> createVariantKeys() {
|
144 |
ilm |
45 |
return Arrays.asList(SINGULAR, PLURAL, INDEFINITE_ARTICLE_SINGULAR, INDEFINITE_ARTICLE_PLURAL, DEFINITE_ARTICLE_SINGULAR, DEFINITE_ARTICLE_PLURAL, DEMONSTRATIVE_SINGULAR, DEMONSTRATIVE_PLURAL,
|
|
|
46 |
INDEFINITE_NUMERAL, DEFINITE_NUMERAL, DEMONSTRATIVE_NUMERAL, INDEFINITE_ORDINAL, DEFINITE_ORDINAL);
|
73 |
ilm |
47 |
}
|
|
|
48 |
|
|
|
49 |
@Override
|
|
|
50 |
protected Collection<? extends NounClass> createNounClasses() {
|
|
|
51 |
return Arrays.asList(NounClass.FEMININE, NounClass.MASCULINE);
|
|
|
52 |
}
|
|
|
53 |
|
|
|
54 |
public final Phrase createPhrase(final NounClass nounClass, final String singular) {
|
|
|
55 |
return this.createPhrase(nounClass, singular, null);
|
|
|
56 |
}
|
|
|
57 |
|
|
|
58 |
public final Phrase createPhrase(final NounClass nounClass, final String singular, final String plural) {
|
|
|
59 |
if (!this.getNounClasses().contains(nounClass))
|
|
|
60 |
throw new IllegalArgumentException("invalid nounClass : " + nounClass);
|
|
|
61 |
final Phrase res = new Phrase(this, singular, nounClass);
|
|
|
62 |
if (plural != null)
|
|
|
63 |
res.putVariant(PLURAL, plural);
|
|
|
64 |
return res;
|
|
|
65 |
}
|
|
|
66 |
|
|
|
67 |
@Override
|
|
|
68 |
public String getVariant(Phrase noun, VariantKey key) {
|
|
|
69 |
final String res;
|
144 |
ilm |
70 |
if (key.equals(SINGULAR)) {
|
73 |
ilm |
71 |
res = noun.getBase();
|
144 |
ilm |
72 |
} else if (key.equals(INDEFINITE_ARTICLE_SINGULAR)) {
|
|
|
73 |
res = (noun.getNounClass() == NounClass.FEMININE ? "une " : "un ") + getSingular(noun);
|
|
|
74 |
} else if (key.equals(DEFINITE_ARTICLE_SINGULAR)) {
|
73 |
ilm |
75 |
res = getDefiniteArticle(noun) + getSingular(noun);
|
144 |
ilm |
76 |
} else if (key.equals(DEMONSTRATIVE_SINGULAR)) {
|
73 |
ilm |
77 |
res = getCe(noun) + getSingular(noun);
|
144 |
ilm |
78 |
} else if (key.equals(PLURAL)) {
|
73 |
ilm |
79 |
res = getPlural(noun.getBase());
|
144 |
ilm |
80 |
} else if (key.equals(INDEFINITE_ARTICLE_PLURAL)) {
|
73 |
ilm |
81 |
res = "des " + getPlural(noun);
|
144 |
ilm |
82 |
} else if (key.equals(DEFINITE_ARTICLE_PLURAL)) {
|
73 |
ilm |
83 |
res = "les " + getPlural(noun);
|
144 |
ilm |
84 |
} else if (key.equals(DEMONSTRATIVE_PLURAL)) {
|
73 |
ilm |
85 |
res = "ces " + getPlural(noun);
|
144 |
ilm |
86 |
} else if (key.equals(INDEFINITE_NUMERAL)) {
|
156 |
ilm |
87 |
res = "{0, plural, =0 {auc" + noun.getVariant(INDEFINITE_ARTICLE_SINGULAR) + "} one {# " + getSingular(noun) + "} other {# " + getPlural(noun) + "}}";
|
144 |
ilm |
88 |
} else if (key.equals(DEFINITE_NUMERAL)) {
|
156 |
ilm |
89 |
res = "{0, plural, =0 {auc" + noun.getVariant(INDEFINITE_ARTICLE_SINGULAR) + "} one {" + noun.getVariant(DEFINITE_ARTICLE_SINGULAR) + "} other {les # " + getPlural(noun) + "}}";
|
144 |
ilm |
90 |
} else if (key.equals(DEMONSTRATIVE_NUMERAL)) {
|
156 |
ilm |
91 |
res = "{0, plural, =0 {auc" + noun.getVariant(INDEFINITE_ARTICLE_SINGULAR) + "} one {" + noun.getVariant(DEMONSTRATIVE_SINGULAR) + "} other {ces # " + getPlural(noun) + "}}";
|
144 |
ilm |
92 |
} else if (key.equals(DEFINITE_ORDINAL) || key.equals(INDEFINITE_ORDINAL)) {
|
|
|
93 |
final boolean estFéminin = noun.getNounClass() == NounClass.FEMININE;
|
|
|
94 |
final String article = key.equals(DEFINITE_ORDINAL) ? (estFéminin ? "la " : "le ") : "";
|
|
|
95 |
res = article + "{0, ordinal, %digits-ordinal" + (estFéminin ? "-feminine" : "") + "} " + getSingular(noun);
|
|
|
96 |
} else {
|
73 |
ilm |
97 |
res = null;
|
144 |
ilm |
98 |
}
|
|
|
99 |
|
73 |
ilm |
100 |
return res;
|
|
|
101 |
}
|
|
|
102 |
|
|
|
103 |
protected String getDefiniteArticle(Phrase noun) {
|
|
|
104 |
if (startsWithVowel(noun.getBase()))
|
|
|
105 |
return "l’";
|
|
|
106 |
else if (noun.getNounClass() == NounClass.MASCULINE)
|
|
|
107 |
return "le ";
|
|
|
108 |
else
|
|
|
109 |
return "la ";
|
|
|
110 |
}
|
|
|
111 |
|
|
|
112 |
protected boolean startsWithVowel(String s) {
|
|
|
113 |
String firstLetter = s.substring(0, 1).toLowerCase(getLocale());
|
|
|
114 |
// handle "habitude", MAYBE handle h aspiré (e.g. "haricot")
|
|
|
115 |
if (firstLetter.equals("h"))
|
|
|
116 |
firstLetter = s.substring(1, 2).toLowerCase(getLocale());
|
|
|
117 |
// handle "éclairage"
|
|
|
118 |
final char char0 = Normalizer.normalize(firstLetter, Form.NFD).charAt(0);
|
|
|
119 |
return char0 == 'a' || char0 == 'e' || char0 == 'i' || char0 == 'o' || char0 == 'u' || char0 == 'y';
|
|
|
120 |
}
|
|
|
121 |
|
|
|
122 |
protected String getSingular(Phrase noun) {
|
|
|
123 |
final String res = noun.getVariant(SINGULAR);
|
|
|
124 |
return res == null ? noun.getBase() : res;
|
|
|
125 |
}
|
|
|
126 |
|
|
|
127 |
protected String getPlural(Phrase noun) {
|
|
|
128 |
final String res = noun.getVariant(PLURAL);
|
|
|
129 |
return res == null ? getPlural(noun.getBase()) : res;
|
|
|
130 |
}
|
|
|
131 |
|
|
|
132 |
protected String getPlural(String noun) {
|
|
|
133 |
final int l = noun.length();
|
|
|
134 |
final char lastChar = noun.charAt(l - 1);
|
|
|
135 |
if (lastChar == 's' || lastChar == 'x' || lastChar == 'z')
|
|
|
136 |
return noun;
|
|
|
137 |
else if (noun.endsWith("al"))
|
|
|
138 |
return noun.substring(0, l - 2) + "aux";
|
|
|
139 |
else
|
|
|
140 |
return noun + 's';
|
|
|
141 |
}
|
|
|
142 |
|
|
|
143 |
private String getCe(Phrase noun) {
|
|
|
144 |
if (noun.getNounClass().equals(NounClass.FEMININE))
|
|
|
145 |
return "cette ";
|
|
|
146 |
else if (startsWithVowel(noun.getBase()))
|
|
|
147 |
return "cet ";
|
|
|
148 |
else
|
|
|
149 |
return "ce ";
|
|
|
150 |
}
|
|
|
151 |
|
|
|
152 |
private static final Pattern LE_LES = Pattern.compile("(\\p{javaWhitespace}*)([Ll][Ee][Ss]?)\\p{javaWhitespace}+");
|
|
|
153 |
|
|
|
154 |
public String de(final String phrase) {
|
|
|
155 |
final Matcher matcher = LE_LES.matcher(phrase);
|
|
|
156 |
if (matcher.lookingAt()) {
|
|
|
157 |
final String le_les_group = matcher.group(2);
|
|
|
158 |
final char d = le_les_group.charAt(0) == 'L' ? 'D' : 'd';
|
|
|
159 |
final String de;
|
|
|
160 |
if (le_les_group.length() == 3)
|
|
|
161 |
de = d + le_les_group.substring(1);
|
|
|
162 |
else
|
|
|
163 |
de = d + (le_les_group.charAt(1) == 'E' ? "U" : "u");
|
|
|
164 |
return matcher.group(1) + de + phrase.substring(matcher.end(2));
|
|
|
165 |
} else if (startsWithVowel(phrase.trim())) {
|
|
|
166 |
return "d’" + phrase;
|
|
|
167 |
} else {
|
|
|
168 |
return "de " + phrase;
|
|
|
169 |
}
|
|
|
170 |
}
|
|
|
171 |
|
|
|
172 |
public String à(final String phrase) {
|
|
|
173 |
final Matcher matcher = LE_LES.matcher(phrase);
|
|
|
174 |
if (matcher.lookingAt()) {
|
|
|
175 |
final String le_les_group = matcher.group(2);
|
|
|
176 |
final String au = (le_les_group.charAt(0) == 'L' ? "A" : "a") + (le_les_group.charAt(1) == 'E' ? "U" : "u");
|
|
|
177 |
final String de;
|
|
|
178 |
if (le_les_group.length() == 3)
|
|
|
179 |
de = au + (le_les_group.charAt(2) == 'S' ? "X" : "x");
|
|
|
180 |
else
|
|
|
181 |
de = au;
|
|
|
182 |
return matcher.group(1) + de + phrase.substring(matcher.end(2));
|
|
|
183 |
} else {
|
|
|
184 |
return "à " + phrase;
|
|
|
185 |
}
|
|
|
186 |
}
|
|
|
187 |
}
|