1
0
Fork 0

Easier contraction typing (#289)

* removed isPunctiationPartOfWords hack and created a new contraction input method that allows typing just anything, instead of predefined list coming from the dictionary

* updated the common compound words and contractions in Bulgarian, Dutch, English and French

* removed some non-sense and rarely used English words

* fixed crashing when trying to find words with apostrophes in the database

* fixed a crash when trying to capitalize single character strings

* improved dictionary validation at build time: spaces are now disallowed
This commit is contained in:
Dimo Karaivanov 2023-06-20 09:29:48 +03:00 committed by GitHub
parent cf766334d6
commit 241a4125b0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
35 changed files with 389 additions and 35214 deletions

View file

@ -54,11 +54,9 @@ To support a new language one needs to:
- `locale` contains the language and the country codes (e.g. "en-US", "es-AR", "it-IT"). Refer to the list of [supported locales in Java](https://www.oracle.com/java/technologies/javase/jdk8-jre8-suported-locales.html#util-text). - `locale` contains the language and the country codes (e.g. "en-US", "es-AR", "it-IT"). Refer to the list of [supported locales in Java](https://www.oracle.com/java/technologies/javase/jdk8-jre8-suported-locales.html#util-text).
- `dictionaryFile` is the name of the dictionary in `assets/` folder. - `dictionaryFile` is the name of the dictionary in `assets/` folder.
- `characterMap` contains the letters and punctuation marks associated with each key. - `characterMap` contains the letters and punctuation marks associated with each key.
- Set `isPunctuationPartOfWords` to `true`, if the dictionary contains words with apostrophes or dashes, such as: `it's`, `you'll`, `a'tje` or `п'ят`. This will allow using 1-key for typing them (they will appear as suggestions). `false` will enable faster typing when apostrophes or other punctuation are not part of the words (no such words will be suggested).
- `abcString` _(optional)_. A custom string to display in ABC mode. By default, the first three letters on 2-key are used (e.g. "ABC" or "АБВ"). Set this if the first letters of the alphabet are _not_ on 2-key, like in Hebrew, or if a different string makes more sense. - `abcString` _(optional)_. A custom string to display in ABC mode. By default, the first three letters on 2-key are used (e.g. "ABC" or "АБВ"). Set this if the first letters of the alphabet are _not_ on 2-key, like in Hebrew, or if a different string makes more sense.
- `hasUpperCase` _(optional)_ set to `false` when the language has no upper- and lowercase letters. For example: Arabic, Hebrew, East Asian - `hasUpperCase` _(optional)_ set to `false` when the language has no upper- and lowercase letters. For example: Arabic, Hebrew, East Asian languages, and so on. The default is `true`.
languages, and so on. The default is `true`. - `name` _(optional)_ is automatically generated and equals the native name of the language (e.g. "English", "Deutsch", "Українська"). However, sometimes, the automatically selected name may be ambiguous. For example, both Portuguese in Portugal and Brazil will default to "Português", so assigning "Português brasileiro" would make it clear it's the language used in Brazil.
- `name` _(optional)_ defaults to the native name of the language (e.g. "English", "Deutsch", "Українська"). Useful to set when the default is ambiguous. For example, both Portuguese in Portugal and Brazil will default to "Português", so assigning "Português brasileiro" would make it clear it's the language used in Brazil.
- Finally, add the new language to the list in `LanguageCollection.java`. You only need to add it in one place, in the constructor. Please, be nice and maintain the alphabetical order. - Finally, add the new language to the list in `LanguageCollection.java`. You only need to add it in one place, in the constructor. Please, be nice and maintain the alphabetical order.

View file

@ -490,6 +490,7 @@
пия 170 пия 170
плу плу
плю плю
по-
под 204 под 204
пое пое
пои пои
@ -2246,6 +2247,7 @@
наем 167 наем 167
нает 137 нает 137
наех наех
най-
назе назе
нали 184 нали 184
нане 90 нане 90

Can't render this file because it is too large.

File diff suppressed because it is too large Load diff

View file

@ -1,3 +1,26 @@
c'
ç'
d'
j'
l'
m'
n'
s'
t'
y'
qu'
-ce
-ci
-il
-la
-toi
-elle
-nous
-vous
jusqu'
lorsqu'
puisqu'
quoiqu'
abaissa 59 abaissa 59
abaissable abaissable
abaissables abaissables

Can't render this file because it is too large.

View file

@ -1,14 +1,19 @@
's-Graveland 94 Gravendeel 95
's-Gravendeel 95 Gravenhaags
's-Gravenhaags Gravenhage 129
's-Gravenhage 129 Gravenhagenaar
's-Gravenhagenaar Gravenmoer
's-Gravenmoer Gravenzande 103
's-Gravenzande 103 Gravenzander
's-Gravenzander Gravenzands
's-Gravenzands Hertogenbosch 129
's-Hertogenbosch 129 'k
't 180 's
't
's-
m'n
d'r
da's
A-attest A-attest
A-attesten A-attesten
A-biljet A-biljet
@ -23,7 +28,6 @@ A-omroep
A-omroepen A-omroepen
A-selectie 92 A-selectie 92
A-status 90 A-status 90
A.D.
AAA 109 AAA 109
AAW 96 AAW 96
AAW-voorziening AAW-voorziening
@ -1928,7 +1932,6 @@ ayses
aytekin aytekin
ayten ayten
aytens aytens
az.
azad azad
azads azads
azarkan azarkan
@ -5025,7 +5028,6 @@ chilenen 91
chili 110 chili 110
chimène chimène
chimènes chimènes
chin.
china 163 china 163
china's 104 china's 104
chinees 119 chinees 119
@ -5719,7 +5721,6 @@ d-day 98
d-sluiting d-sluiting
d-trein 80 d-trein 80
d-treinen d-treinen
d.v.
ddt 99 ddt 99
deet 99 deet 99
dna 144 dna 144
@ -10520,8 +10521,6 @@ gül 85
güls güls
h-bom h-bom
h-bommen h-bommen
h.k.h.
h.m.
hrm 122 hrm 122
htm 111 htm 111
html 127 html 127
@ -15930,7 +15929,6 @@ l-profiel
l-profielen l-profielen
l-vormig 86 l-vormig 86
l-vormige 104 l-vormige 104
l.b.
lan 99 lan 99
lgpl lgpl
lto 75 lto 75
@ -19174,7 +19172,6 @@ mexx'
meyer 123 meyer 123
meyerode meyerode
meys 75 meys 75
mgr.
mia 90 mia 90
mia's 72 mia's 72
mica 97 mica 97
@ -19962,12 +19959,6 @@ mälarmeer
mélanie 73 mélanie 73
mélanies mélanies
münchen 135 münchen 135
n.b.
n.h.
n.n.
n.o.
n.v.
n.w.
nam 121 nam 121
nap 95 nap 95
nasa 125 nasa 125
@ -20249,7 +20240,6 @@ neals
nebahat 81 nebahat 81
nebahats nebahats
nebbeling nebbeling
ned.
Neder-Betuwe 90 Neder-Betuwe 90
Neder-Californië Neder-Californië
Neder-Congo Neder-Congo
@ -21093,7 +21083,6 @@ nyssa
nyssa's nyssa's
nürnberg 102 nürnberg 102
o-benen 78 o-benen 78
o.l.v.
ocmw 132 ocmw 132
ocmw's 108 ocmw's 108
OCMW-raad 88 OCMW-raad 88
@ -21525,7 +21514,6 @@ opdorp 81
opel 132 opel 132
opels 84 opels 84
opendocument opendocument
openoffice.org
opentaal 113 opentaal 113
opgeldenaken opgeldenaken
opgenoort opgenoort
@ -23029,7 +23017,6 @@ quitoos
quitoër quitoër
quix 72 quix 72
qureshi qureshi
r.i.p.
ram 115 ram 115
rdw 124 rdw 124
ret 117 ret 117
@ -26750,8 +26737,6 @@ srananmans
sranantongo 88 sranantongo 88
srebrenica 117 srebrenica 117
sri 78 sri 78
st.-eustatius
st.-maarten
staaks staaks
staals staals
staarink staarink
@ -26847,7 +26832,6 @@ stavast 80
stavele 76 stavele 76
stavenga stavenga
stavleu stavleu
stct.
steef 85 steef 85
steefs steefs
steegers steegers
@ -29997,8 +29981,6 @@ vänermeer
vättermeer vättermeer
véronique 99 véronique 99
véroniques véroniques
w.
w.v.str.
wa 115 wa 115
WA-verzekering 93 WA-verzekering 93
WAM-sticker WAM-sticker
@ -31611,8 +31593,6 @@ z-verpleegkundige
z-verpleegkundigen z-verpleegkundigen
z-vormig z-vormig
z-vormige z-vormige
z.h.
z.k.h.
zaaijer 82 zaaijer 82
zaan 89 zaan 89
zaandam 132 zaandam 132
@ -32158,13 +32138,6 @@ a-priorisch 79
a-priorische a-priorische
a-prioristisch 79 a-prioristisch 79
a-prioristische 81 a-prioristische 81
a.d.h.v.
a.g.v.
a.h.w.
a.j.b.
a.m.
a.s.
a.u.b.
aagt 84 aagt 84
aagtappel 80 aagtappel 80
aagtappels 79 aagtappels 79
@ -35328,7 +35301,6 @@ aanvuring 85
aanvuurde 84 aanvuurde 84
aanvuurden 82 aanvuurden 82
aanvuurt 83 aanvuurt 83
aanw.
aanwaai 80 aanwaai 80
aanwaaide 80 aanwaaide 80
aanwaaiden 78 aanwaaiden 78
@ -38653,7 +38625,6 @@ afasiepatiënten
afat afat
afatisch 80 afatisch 80
afatische 84 afatische 84
afb.
afbad 77 afbad 77
afbak 85 afbak 85
afbakbrood afbakbrood
@ -38907,7 +38878,6 @@ afbuigmagneet 81
afbuigt 94 afbuigt 94
afcentiemen afcentiemen
afchecken afchecken
afd.
afdaal 84 afdaal 84
afdaalde 95 afdaalde 95
afdaalden 92 afdaalden 92
@ -43068,7 +43038,6 @@ afwrijft 85
afwrijven 92 afwrijven 92
afwrijvingen 77 afwrijvingen 77
afwringen 82 afwringen 82
afz.
afzaag 84 afzaag 84
afzaagde 82 afzaagde 82
afzaagden 84 afzaagden 84
@ -45222,7 +45191,6 @@ amuzikaal
amygdala 99 amygdala 99
amylose 72 amylose 72
amyotrofie 80 amyotrofie 80
an.
anaal 121 anaal 121
anabaptisme 81 anabaptisme 81
anabaptist 81 anabaptist 81
@ -47864,7 +47832,6 @@ aronskelken 83
aroom 82 aroom 82
arpeggio 89 arpeggio 89
arpeggio's 81 arpeggio's 81
arr.
arrangeer 82 arrangeer 82
arrangeerde 93 arrangeerde 93
arrangeerden 82 arrangeerden 82
@ -50164,9 +50131,6 @@ aïssen 73
b's b's
b'tje b'tje
b'tjes b'tjes
b.d.
b.g.g.
b.v.d.
baad 88 baad 88
baadde 96 baadde 96
baadden 89 baadden 89
@ -53282,7 +53246,6 @@ bazuintje 82
bazuintjes 81 bazuintjes 81
bbp 121 bbp 121
bbp-groei 81 bbp-groei 81
bc.
beaam 90 beaam 90
beaamd 98 beaamd 98
beaamde 104 beaamde 104
@ -61835,7 +61798,6 @@ betrouwde 84
betrouwden 81 betrouwden 81
betrouwen 99 betrouwen 99
betrouwt 83 betrouwt 83
bett.
betuig 99 betuig 99
betuigd 111 betuigd 111
betuigde 106 betuigde 106
@ -64941,7 +64903,6 @@ bijkrijgt 86
bijkwam 98 bijkwam 98
bijkwamen 91 bijkwamen 91
bijl 129 bijl 129
bijl.
bijladen 88 bijladen 88
bijlag 87 bijlag 87
bijlage 157 bijlage 157
@ -65325,7 +65286,6 @@ bijtten 79
bijtwond 77 bijtwond 77
bijtwonden 82 bijtwonden 82
bijtwondje bijtwondje
bijv.
bijvak 95 bijvak 95
bijvakken 90 bijvakken 90
bijvakprogramma 80 bijvakprogramma 80
@ -68420,7 +68380,6 @@ bluts 87
blutsen 89 blutsen 89
blutst 81 blutst 81
blutste 76 blutste 76
blz.
blèrde 82 blèrde 82
blèrden 81 blèrden 81
blèren 97 blèren 97
@ -76207,10 +76166,8 @@ buy-outs
buzzer 85 buzzer 85
buzzers 75 buzzers 75
bv'tjes bv'tjes
bv.
bvba 119 bvba 119
bvba's bvba's
bw.
bye 108 bye 108
byebye byebye
byes byes
@ -76249,9 +76206,6 @@ c'tjes
c-pion c-pion
c-sleutel c-sleutel
c-sleutels c-sleutels
c.q.
c.s.
ca.
caban 82 caban 82
cabans 83 cabans 83
cabaret 123 cabaret 123
@ -85268,10 +85222,6 @@ d's 84
d'tje d'tje
d'tjes d'tjes
d-pion d-pion
d.d.
d.i.
d.m.v.
d.w.z.
db 132 db 132
daad 149 daad 149
daadkracht 122 daadkracht 122
@ -86782,7 +86732,6 @@ daze
dazen 97 dazen 97
dc 143 dc 143
dc's dc's
dd.
de 255 de 255
de-escalatie 77 de-escalatie 77
de-escalaties de-escalaties
@ -89593,7 +89542,6 @@ dezulken 101
deïsme 89 deïsme 89
deïst 86 deïst 86
deïsten 86 deïsten 86
dhr.
dia 123 dia 123
dia's 119 dia's 119
dia-avond dia-avond
@ -92158,7 +92106,6 @@ dittografieën 77
ditzelfde 118 ditzelfde 118
diuretica 93 diuretica 93
diureticum 93 diureticum 93
div.
divalifeest divalifeest
divalioptocht divalioptocht
divalioptochten divalioptochten
@ -95906,9 +95853,7 @@ dozijnen 97
dozijntje 82 dozijntje 82
dozijntjes 82 dozijntjes 82
dpi 111 dpi 111
dr.
dra 115 dra 115
dra.
draad 153 draad 153
draadachtig 83 draadachtig 83
draadachtige 89 draadachtige 89
@ -97578,8 +97523,6 @@ droste-effect
drostendiensten 82 drostendiensten 82
drostschap 80 drostschap 80
drozen 79 drozen 79
drs.
drs.-titel
drug 123 drug 123
drugbaron drugbaron
drugbeleid 93 drugbeleid 93
@ -98141,7 +98084,6 @@ druïdetempel
dryade 92 dryade 92
dryaden 84 dryaden 84
drycleaning drycleaning
ds.
dtp 80 dtp 80
dtp-prik dtp-prik
dtp-prikken dtp-prikken
@ -99536,12 +99478,6 @@ e-pion
e-snaar 78 e-snaar 78
e-zine 98 e-zine 98
e-zines 77 e-zines 77
e.a.
e.d.
e.e.a.
e.o.
e.v.
e.v.a.
earlgreythee earlgreythee
earnings earnings
eau-de-colognefles 80 eau-de-colognefles 80
@ -103004,7 +102940,6 @@ enveloppenfinanciering
enveloppetje enveloppetje
environment 97 environment 97
environments 72 environments 72
enz.
enzoverder 93 enzoverder 93
enzovoort 144 enzovoort 144
enzovoorts 133 enzovoorts 133
@ -103963,7 +103898,6 @@ etappezege 94
etappezeges 76 etappezeges 76
etatistisch etatistisch
etatistische etatistische
etc.
eten 181 eten 181
etend 97 etend 97
etende 101 etende 101
@ -104600,7 +104534,6 @@ evolutionistisch 83
evolutionistische 82 evolutionistische 82
evoqueerde evoqueerde
evoqueren 80 evoqueren 80
evt.
ex 149 ex 149
ex-kamerleden ex-kamerleden
ex-kamerlid ex-kamerlid
@ -104956,7 +104889,6 @@ excitatie 92
excitaties excitaties
exciteerde exciteerde
exciteren 83 exciteren 83
excl.
exclamatie 79 exclamatie 79
exclamaties 81 exclamaties 81
exclave 91 exclave 91
@ -105784,7 +105716,6 @@ f-sleutel 81
f-sleutels 76 f-sleutels 76
fa 123 fa 123
fa's fa's
fa.
faal 98 faal 98
faalangst 117 faalangst 117
faalangsten faalangsten
@ -106188,7 +106119,6 @@ falsifieert 82
falsifiëren 84 falsifiëren 84
falsifiëring 78 falsifiëring 78
falsifiëringen falsifiëringen
fam.
fameus 98 fameus 98
fameust 77 fameust 77
fameuze 122 fameuze 122
@ -107751,7 +107681,6 @@ fietszoektocht 75
fietszoektochten fietszoektochten
fifties 93 fifties 93
fiftyfifty 85 fiftyfifty 85
fig.
figaro 83 figaro 83
figaro's figaro's
figgelen 78 figgelen 78
@ -110574,7 +110503,6 @@ foxtrotte 80
foxtrotten 80 foxtrotten 80
foyer 117 foyer 117
foyers 93 foyers 93
fr.
fraai 148 fraai 148
fraaie 152 fraaie 152
fraaier 107 fraaier 107
@ -111851,7 +111779,6 @@ g'tjes
g-sleutel 81 g-sleutel 81
g-sleutels g-sleutels
g-spot 76 g-spot 76
g.g.d.
ga 183 ga 183
gaaf 141 gaaf 141
gaafheid 102 gaafheid 102
@ -113444,7 +113371,6 @@ geavanceerder 101
geavanceerdere 92 geavanceerdere 92
geavondmaald 77 geavondmaald 77
geavontuurd 82 geavontuurd 82
geb.
gebaad 98 gebaad 98
gebaald 81 gebaald 81
gebaand 103 gebaand 103
@ -119363,7 +119289,6 @@ geluwd 97
geluwde 83 geluwde 83
gelyncht 97 gelyncht 97
gelynchte 82 gelynchte 82
gem.
gemaaid 122 gemaaid 122
gemaaide 100 gemaaide 100
gemaakt 193 gemaakt 193
@ -123739,7 +123664,6 @@ gesynthetiseerd 97
gesynthetiseerde 86 gesynthetiseerde 86
gesystematiseerd 87 gesystematiseerd 87
gesystematiseerde 85 gesystematiseerde 85
get.
getaakt 81 getaakt 81
getaald 82 getaald 82
getaand 89 getaand 89
@ -144284,19 +144208,6 @@ i-bankieren
i-grec 81 i-grec 81
i-grecs i-grecs
i-mode 83 i-mode 83
i.c.
i.c.m.
i.e.
i.h.a.
i.h.b.
i.m.
i.o.
i.o.v.
i.p.v.
i.s.m.
i.t.t.
i.v.m.
i.z.g.st.
ipod 130 ipod 130
ipods 95 ipods 95
ia 133 ia 133
@ -145935,7 +145846,6 @@ inciviek 81
incivieke incivieke
incivieken incivieken
incivisme 80 incivisme 80
incl.
inclinatie 90 inclinatie 90
inclinatiekompas 74 inclinatiekompas 74
inclinaties 82 inclinaties 82
@ -147169,7 +147079,6 @@ infuuspompen 78
infuuspompjes infuuspompjes
infuusvloeistof infuusvloeistof
infuusvloeistoffen infuusvloeistoffen
ing.
ingaan 146 ingaan 146
ingaand 97 ingaand 97
ingaande 116 ingaande 116
@ -152012,7 +151921,6 @@ ionosferisch
ionosferische ionosferische
ippon 94 ippon 94
ippons ippons
ir.
irenisch 84 irenisch 84
irenische 81 irenische 81
iridium 90 iridium 90
@ -153492,7 +153400,6 @@ jezuïetenstijl 74
jezuïtisch 78 jezuïtisch 78
jezuïtische 83 jezuïtische 83
jezuïtisme 77 jezuïtisme 77
jhr.
jicht 114 jicht 114
jichtaanval 85 jichtaanval 85
jichtaanvallen 83 jichtaanvallen 83
@ -153528,8 +153435,6 @@ jip-en-janneketaal
jippie 89 jippie 89
jiujitsu 90 jiujitsu 90
jive 89 jive 89
jkvr.
jl.
jobaanbieding jobaanbieding
jobaanbiedingen 79 jobaanbiedingen 79
jobaanbod jobaanbod
@ -154017,7 +153922,6 @@ joyriders
joyriding 88 joyriding 88
joystick 108 joystick 108
joysticks 90 joysticks 90
jr.
jubee 82 jubee 82
jubel 97 jubel 97
jubelde 96 jubelde 96
@ -154414,7 +154318,6 @@ juxtapositie 87
k's 74 k's 74
k'tje k'tje
k'tjes k'tjes
k.k.
khz 114 khz 114
kj 94 kj 94
kw 131 kw 131
@ -178201,7 +178104,6 @@ librettoschrijver
librije 86 librije 86
librijen 78 librijen 78
librium 81 librium 81
lic.
licentiaat 109 licentiaat 109
licentiaatsdiploma licentiaatsdiploma
licentiaatsdiploma's licentiaatsdiploma's
@ -183132,16 +183034,6 @@ m'etjes
m's m's
m-bankierde m-bankierde
m-bankieren m-bankieren
m.
m.a.w.
m.b.t.
m.b.v.
m.i.
m.i.v.
m.m.
m.m.v.
m.n.
m.u.v.
m/s m/s
ma's 92 ma's 92
maag 150 maag 150
@ -186676,7 +186568,6 @@ mavoleerlingen
mavoniveau mavoniveau
mavoscholen mavoscholen
mavoschool mavoschool
max.
maxi 111 maxi 111
maximaal 166 maximaal 166
maximale 158 maximale 158
@ -190491,7 +190382,6 @@ meurt 77
meute 118 meute 118
meuten 84 meuten 84
meutes 86 meutes 86
mevr.
mevrouw 162 mevrouw 162
mevrouwde 78 mevrouwde 78
mevrouwen 93 mevrouwen 93
@ -191969,7 +191859,6 @@ mimosa 91
mimosa's mimosa's
min-maxcontract min-maxcontract
min-maxcontracten min-maxcontracten
min.
minacht 94 minacht 94
minachten 98 minachten 98
minachtend 106 minachtend 106
@ -193069,9 +192958,7 @@ mixtures
mixtuur 83 mixtuur 83
mkb 119 mkb 119
ml 146 ml 146
mld.
mlk-school mlk-school
mln.
mm 167 mm 167
mnemotechniek 78 mnemotechniek 78
mnemotechnisch 83 mnemotechnisch 83
@ -195711,7 +195598,6 @@ mozetta's
mozzarella 116 mozzarella 116
mp 98 mp 98
mp's mp's
mr.
ms 120 ms 120
mts 88 mts 88
mu 111 mu 111
@ -196751,7 +196637,6 @@ muzikantesk 78
muzikanteske muzikanteske
muzisch 90 muzisch 90
muzische 101 muzische 101
mw.
mycelium 97 mycelium 97
mycologen 85 mycologen 85
mycologie 84 mycologie 84
@ -196829,9 +196714,6 @@ n'en
n'etje 75 n'etje 75
n'etjes n'etjes
n's 72 n's 72
n.a.v.
n.o.t.k.
n.v.t.
na 119 na 119
na-aapt na-aapt
na-apen 93 na-apen 93
@ -201545,8 +201427,6 @@ niëlleerde 74
niëlleren 78 niëlleren 78
njet 91 njet 91
njonja 80 njonja 80
nl.
nl.openoffice.org
nm 121 nm 121
no-claim 97 no-claim 97
no-claimkorting 92 no-claimkorting 92
@ -201561,7 +201441,6 @@ no-nonsense 111
no-nonsensebeleid no-nonsensebeleid
no-nonsensepolitiek no-nonsensepolitiek
no-showstudent no-showstudent
no.
noachitisch noachitisch
noachitische noachitische
nobele 120 nobele 120
@ -202435,8 +202314,6 @@ novum 100
nozem 91 nozem 91
nozempje nozempje
nozems 92 nozems 92
nr.
nrs.
nu 138 nu 138
nuance 125 nuance 125
nuanceer 83 nuanceer 83
@ -202657,14 +202534,6 @@ nymfomanie 82
o's 85 o's 85
o'tje o'tje
o'tjes o'tjes
o.a.
o.b.v.
o.i.
o.i.d.
o.m.
o.t.t.
o.v.t.
o.v.v.
oase 126 oase 126
oasen 90 oasen 90
oases 100 oases 100
@ -208408,7 +208277,6 @@ onfrisser 75
onfrist 78 onfrist 78
onfunctioneel onfunctioneel
onfunctionele onfunctionele
ong.
ongaar ongaar
ongaarne 99 ongaarne 99
ongans 88 ongans 88
@ -221699,12 +221567,6 @@ oölieten 81
p's 78 p's 78
p'tje p'tje
p'tjes p'tjes
p.
p.a.
p.m.
p.o.
p.p.
p.w.
ph 129 ph 129
ph's ph's
ph-neutraal ph-neutraal
@ -222284,7 +222146,6 @@ pafte 84
paften 80 paften 80
pafzak 76 pafzak 76
pafzakken 75 pafzakken 75
pag.
pagaai 85 pagaai 85
pagaaide 81 pagaaide 81
pagaaiden 77 pagaaiden 77
@ -230065,7 +229926,6 @@ plissérok
plissérokken plissérokken
plissés 84 plissés 84
plistoceen plistoceen
plm.
ploeg 158 ploeg 158
ploegachtervolging ploegachtervolging
ploegarts 72 ploegarts 72
@ -230503,7 +230363,6 @@ pluvier 80
pluvieren 81 pluvieren 81
pluviometer 84 pluviometer 84
pluviometers 82 pluviometers 82
plv.
pneumatiek 92 pneumatiek 92
pneumatisch 106 pneumatisch 106
pneumatische 117 pneumatische 117
@ -236150,7 +236009,6 @@ proeverij 118
proeverijen 106 proeverijen 106
proevers 94 proevers 94
prof 145 prof 145
prof.
profaan 93 profaan 93
profaanst profaanst
profafdeling profafdeling
@ -238598,8 +238456,6 @@ pythons 90
q's q's
q'tje q'tje
q'tjes q'tjes
q.e.d.
q.q.
qat 94 qat 94
qua 162 qua 162
quad 110 quad 110
@ -238768,7 +238624,6 @@ r'en
r'etje r'etje
r'etjes r'etjes
r's r's
r.-k.
ra 122 ra 122
ra's 88 ra's 88
raad 168 raad 168
@ -241970,7 +241825,6 @@ recyclingbedrijf 86
recyclingbedrijven 73 recyclingbedrijven 73
recyclingproces recyclingproces
red 141 red 141
red.
redacteur 138 redacteur 138
redacteuren 122 redacteuren 122
redacteurs 105 redacteurs 105
@ -245250,7 +245104,6 @@ resort 130
resorts 112 resorts 112
resource 107 resource 107
resources 118 resources 118
resp.
respect 158 respect 158
respectabel 105 respectabel 105
respectabele 115 respectabele 115
@ -251073,8 +250926,6 @@ s'en 72
s'je s'je
s'jes s'jes
s's s's
s.j.
s.v.p.
sa 121 sa 121
saai 142 saai 142
saaie 133 saaie 133
@ -269364,7 +269215,6 @@ squasht 80
squashte squashte
squaw 82 squaw 82
squaws 81 squaws 81
sr.
sta 156 sta 156
sta-in-de-weg 94 sta-in-de-weg 94
sta-in-de-wegs 80 sta-in-de-wegs 80
@ -279562,16 +279412,6 @@ t'tje
t'tjes t'tjes
t-groep t-groep
t-groepen t-groepen
t.a.v.
t.b.v.
t.g.v.
t.h.t.
t.h.v.
t.n.v.
t.o.v.
t.w.
t.w.v.
t.z.t.
taai 124 taai 124
taaie 121 taaie 121
taaien 87 taaien 87
@ -298781,16 +298621,6 @@ uzi's 81
v's v's
v'tje v'tje
v'tjes v'tjes
v.
v.chr.
v.d.
v.h.
v.l.n.r.
v.r.n.l.
v.t.t.
v.v.
v.v.t.
v.w.b.
va 138 va 138
va-banque 75 va-banque 75
va-et-vient 82 va-et-vient 82
@ -304041,7 +303871,6 @@ verfwerken
verfwinkel 89 verfwinkel 89
verfwinkels 82 verfwinkels 82
verg 104 verg 104
verg.
verga 109 verga 109
vergaan 132 vergaan 132
vergaand 108 vergaand 108
@ -312173,7 +312002,6 @@ vezelvlies
vezelvliezen vezelvliezen
vezelwortels 77 vezelwortels 77
vezen 81 vezen 81
vgl.
via 193 via 193
viaduct 126 viaduct 126
viaducten 111 viaducten 111
@ -315274,8 +315102,6 @@ vmbo-leerling
vmbo-leerlingen 91 vmbo-leerlingen 91
vmbo-scholen 84 vmbo-scholen 84
vmbo-school 80 vmbo-school 80
vnl.
vnw.
vocaal 114 vocaal 114
vocabulaire 112 vocabulaire 112
vocabulaires 87 vocabulaires 87
@ -319604,7 +319430,6 @@ voorwoord 127
voorwoorden 87 voorwoorden 87
voorworp 79 voorworp 79
voorworpen 77 voorworpen 77
voorz.
voorzaal 86 voorzaal 86
voorzag 130 voorzag 130
voorzagen 111 voorzagen 111
@ -321752,7 +321577,6 @@ vruchtzak 79
vruchtzakje 74 vruchtzakje 74
vruchtzakken vruchtzakken
vruchtzetting 94 vruchtzetting 94
vs.
vuig 89 vuig 89
vuige 100 vuige 100
vuiger 81 vuiger 81
@ -322255,8 +322079,6 @@ véél 132
w's w's
w'tje w'tje
w'tjes w'tjes
w.o.
w.v.t.t.k.
waad 88 waad 88
waadbaar 78 waadbaar 78
waadbare 80 waadbare 80
@ -333505,7 +333327,6 @@ wurmen 108
wurmpje 83 wurmpje 83
wurmpjes 81 wurmpjes 81
wurmt 92 wurmt 92
ww.
www 174 www 174
wyandotte wyandotte
wybertje 81 wybertje 81
@ -333633,11 +333454,6 @@ z'n 171
z's z's
z'tje z'tje
z'tjes z'tjes
z.g.
z.g.a.n.
z.i.
z.o.z.
z.s.m.
zaad 146 zaad 146
zaadbakje 81 zaadbakje 81
zaadbakjes 81 zaadbakjes 81
@ -336652,7 +336468,6 @@ zeverden 80
zeverlap 78 zeverlap 78
zeverlappen 79 zeverlappen 79
zevert 84 zevert 84
zgn.
zich 210 zich 210
zicht 162 zicht 162
zichtas 77 zichtas 77

Can't render this file because it is too large.

View file

@ -86,29 +86,6 @@ def getReleaseVersion = { ->
return "${getVersionName()} (${getCurrentGitHash()})" return "${getVersionName()} (${getCurrentGitHash()})"
} }
def isPunctuationInWordsAllowed (String dictionaryFile) {
boolean isAllowed = false
file("${project.projectDir}/src/io/github/sspanak/tt9/languages/definitions").listFiles().each { file ->
boolean isTheDefinitionFile = false
file.eachLine {line ->
if (line.contains(dictionaryFile)) {
isTheDefinitionFile = true
}
}
if (isTheDefinitionFile) {
file.eachLine {line ->
if (line.matches(".+?isPunctuationPartOfWords\\s*=\\s*true.+?")) {
isAllowed = true
}
}
}
}
return isAllowed
}
task validateDictionaries { task validateDictionaries {
inputs.dir fileTree(dir:'assets', excludes:['dict.properties']) inputs.dir fileTree(dir:'assets', excludes:['dict.properties'])
outputs.file "${project.buildDir}/dict.validation.txt" outputs.file "${project.buildDir}/dict.validation.txt"
@ -116,7 +93,6 @@ task validateDictionaries {
doLast { doLast {
final String CSV_DELIMITER = ' ' // TAB final String CSV_DELIMITER = ' ' // TAB
final GEOGRAPHICAL_NAME = ~"[A-Z]\\w+-[^\\n]+" final GEOGRAPHICAL_NAME = ~"[A-Z]\\w+-[^\\n]+"
final PUNCTUATION_CHARS = ~".*?\\p{Punct}(?<!-).*?"
final MAX_ERRORS = 50 final MAX_ERRORS = 50
String errors = "" String errors = ""
@ -131,7 +107,6 @@ task validateDictionaries {
println "Validating dictionary: " + file.name println "Validating dictionary: " + file.name
def isPunctuationAllowed = isPunctuationInWordsAllowed(file.name)
def uniqueWords = [:] def uniqueWords = [:]
int lineNumber = 0 int lineNumber = 0
@ -151,6 +126,13 @@ task validateDictionaries {
return return
} }
if (line.contains(" ")) {
isFileValid = false
errorCount++
errors += "Dictionary '" + file.name + "' is invalid. Found space on line " + lineNumber + ". Make sure each word is on a new line. Phrases are not allowed.\n"
return
}
String[] parts = line.split(CSV_DELIMITER, 2) String[] parts = line.split(CSV_DELIMITER, 2)
String word = parts[0] String word = parts[0]
String frequency = parts.length > 1 ? parts[1] : "" String frequency = parts.length > 1 ? parts[1] : ""
@ -179,12 +161,6 @@ task validateDictionaries {
errors += "Dictionary '" + file.name + "' is invalid. Found a single letter: '" + word + "' on line " + lineNumber + ". Only uppercase single letters are allowed. The rest of the alphabet will be added automatically.\n" errors += "Dictionary '" + file.name + "' is invalid. Found a single letter: '" + word + "' on line " + lineNumber + ". Only uppercase single letters are allowed. The rest of the alphabet will be added automatically.\n"
} }
if (!isPunctuationAllowed && word.matches(PUNCTUATION_CHARS)) {
isFileValid = false
errorCount++
errors += "Dictionary '" + file.name + "' is invalid. Found a punctuation mark in word: '" + word + "' on line " + lineNumber + ". Remove all punctuation characters when the language definition disallows them or update the definition.\n"
}
String uniqueWordKey = word ==~ GEOGRAPHICAL_NAME ? word : word.toLowerCase() String uniqueWordKey = word ==~ GEOGRAPHICAL_NAME ? word : word.toLowerCase()
if (uniqueWords[uniqueWordKey] != null && uniqueWords[uniqueWordKey] == true) { if (uniqueWords[uniqueWordKey] != null && uniqueWords[uniqueWordKey] == true) {
isFileValid = false isFileValid = false
@ -235,21 +211,12 @@ android {
defaultConfig { defaultConfig {
minSdkVersion 19 minSdkVersion 19
//noinspection ExpiredTargetSdkVersion
targetSdk 30 targetSdk 30
versionCode getVersionCode() versionCode getVersionCode()
versionName getVersionName() versionName getVersionName()
} }
// http://stackoverflow.com/a/19130098
// signingConfigs {
// release {
// storeFile file(System.getenv("KEYSTORE"))
// storePassword System.getenv("KEYSTORE_PASS")
// keyAlias System.getenv("KEY_ALIAS")
// keyPassword System.getenv("KEY_ALIAS_PASS")
// }
// }
//
buildTypes { buildTypes {
debug { data -> debug { data ->
data.buildConfigField 'String', 'VERSION_FULL', "\"${getDebugVersion()}\"" data.buildConfigField 'String', 'VERSION_FULL', "\"${getDebugVersion()}\""

View file

@ -0,0 +1,43 @@
package io.github.sspanak.tt9;
import java.util.regex.Pattern;
public class TextTools {
private static final Pattern containsOtherThan1 = Pattern.compile("[02-9]");
private static final Pattern previousIsLetter = Pattern.compile("\\p{L}$");
private static final Pattern nextIsPunctuation = Pattern.compile("^\\p{Punct}");
private static final Pattern nextToWord = Pattern.compile("\\b$");
private static final Pattern startOfSentence = Pattern.compile("(?<!\\.)(^|[.?!¿¡])\\s*$");
public static boolean containsOtherThan1(String str) {
return str != null && containsOtherThan1.matcher(str).find();
}
public static boolean isNextToWord(String str) {
return str != null && nextToWord.matcher(str).find();
}
public static boolean isStartOfSentence(String str) {
return str != null && startOfSentence.matcher(str).find();
}
public static boolean nextIsPunctuation(String str) {
return str != null && nextIsPunctuation.matcher(str).find();
}
public static boolean previousIsLetter(String str) {
return str != null && previousIsLetter.matcher(str).find();
}
public static boolean startsWithWhitespace(String str) {
return str != null && !str.isEmpty() && (str.charAt(0) == ' ' || str.charAt(0) == '\n' || str.charAt(0) == '\t');
}
public static boolean startsWithNumber(String str) {
return str != null && !str.isEmpty() && (str.charAt(0) >= '0' && str.charAt(0) <= '9');
}
public static String removeNonLetters(String str) {
return str != null ? str.replaceAll("\\P{L}", "") : null;
}
}

View file

@ -191,24 +191,13 @@ public class DictionaryDb {
// In case the user has changed the text case, there would be no match. // In case the user has changed the text case, there would be no match.
// Try again with the lowercase equivalent. // Try again with the lowercase equivalent.
String lowercaseWord = "";
if (affectedRows == 0) { if (affectedRows == 0) {
lowercaseWord = word.toLowerCase(language.getLocale()); String lowercaseWord = word.toLowerCase(language.getLocale());
affectedRows = getInstance().wordsDao().incrementFrequency(language.getId(), lowercaseWord, sequence); affectedRows = getInstance().wordsDao().incrementFrequency(language.getId(), lowercaseWord, sequence);
Logger.d("incrementWordFrequency", "Attempting to increment frequency for lowercase variant: " + lowercaseWord); Logger.d("incrementWordFrequency", "Attempting to increment frequency for lowercase variant: " + lowercaseWord);
} }
// Some languages permit appending the punctuation to the end of the words, like so: "try,".
// But there are no such words in the dictionary, so try without the punctuation mark.
if (affectedRows == 0 && language.isPunctuationPartOfWords() && sequence.endsWith("1")) {
String truncatedWord = lowercaseWord.substring(0, word.length() - 1);
String truncatedSequence = sequence.substring(0, sequence.length() - 1);
affectedRows = getInstance().wordsDao().incrementFrequency(language.getId(), truncatedWord, truncatedSequence);
Logger.d("incrementWordFrequency", "Attempting to increment frequency with stripped punctuation: " + truncatedWord);
}
Logger.d("incrementWordFrequency", "Affected rows: " + affectedRows); Logger.d("incrementWordFrequency", "Affected rows: " + affectedRows);
} catch (Exception e) { } catch (Exception e) {
Logger.e( Logger.e(

View file

@ -0,0 +1,39 @@
package io.github.sspanak.tt9.db.migrations;
import androidx.annotation.NonNull;
import androidx.room.migration.Migration;
import androidx.sqlite.db.SupportSQLiteDatabase;
import io.github.sspanak.tt9.Logger;
import io.github.sspanak.tt9.languages.definitions.Dutch;
import io.github.sspanak.tt9.languages.definitions.English;
public class DB11 {
public static final Migration MIGRATION = new Migration(10, 11) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
final String enWords = "'I''d','I''m','d''annunzio','I''ll','I''ve','prud''hon','an''t','bo''s''n','bo''s''ns','bo''sun','bo''suns','bos''n','bos''ns','br''er','ca''canny','could''ve','d''arezzo','d''estaing','e''en','e''er','fo''c''s''le','fo''c''s''les','fo''c''sle','fo''c''sles','ha''penny','he''d','he''ll','how''d','how''re','howe''er','it''d','it''ll','might''ve','must''ve','n''importe','ne''er','nor''easter','nor''wester','o''er','rec''d','sec''y','she''d','she''ll','should''ve','sou''wester','ta''en','that''d','that''ll','they''d','they''ll','they''re','they''ve','we''d','we''ll','we''re','we''ve','whate''er','whatsoe''er','whene''er','where''er','who''d','who''ll','who''re','who''ve','why''d','would''ve','you''d','you''ll','you''re','you''ve','Ch''in','L''Amour','L''Enfant','L''Oreal','L''Ouverture','T''ang','Xi''an'";
final String nlWords = "'''s-Graveland','''s-Gravendeel','''s-Gravenhaags','''s-Gravenhage','''s-Gravenhagenaar','''s-Gravenmoer','''s-Gravenzande','''s-Gravenzander','''s-Gravenzands','''s-Hertogenbosch','''t','A.D.','az.','chin.','d.v.','h.k.h.','h.m.','l.b.','mgr.','n.b.','n.h.','n.n.','n.o.','n.v.','n.w.','ned.','o.l.v.','openoffice.org','r.i.p.','st.-eustatius','st.-maarten','stct.','w.','w.v.str.','z.h.','z.k.h.','a.d.h.v.','a.g.v.','a.h.w.','a.j.b.','a.m.','a.s.','a.u.b.','aanw.','afb.','afd.','afz.','an.','arr.','b.d.','b.g.g.','b.v.d.','bc.','bett.','bijl.','bijv.','blz.','bv.','bw.','c.q.','c.s.','ca.','d.d.','d.i.','d.m.v.','d.w.z.','dd.','dhr.','div.','dr.','dra.','drs.','drs.-titel','ds.','e.a.','e.d.','e.e.a.','e.o.','e.v.','e.v.a.','enz.','etc.','evt.','excl.','fa.','fam.','fig.','fr.','g.g.d.','geb.','gem.','get.','i.c.','i.c.m.','i.e.','i.h.a.','i.h.b.','i.m.','i.o.','i.o.v.','i.p.v.','i.s.m.','i.t.t.','i.v.m.','i.z.g.st.','incl.','ing.','ir.','jhr.','jkvr.','jl.','jr.','k.k.','lic.','m.','m.a.w.','m.b.t.','m.b.v.','m.i.','m.i.v.','m.m.','m.m.v.','m.n.','m.u.v.','max.','mevr.','min.','mld.','mln.','mr.','mw.','n.a.v.','n.o.t.k.','n.v.t.','nl.','nl.openoffice.org','no.','nr.','nrs.','o.a.','o.b.v.','o.i.','o.i.d.','o.m.','o.t.t.','o.v.t.','o.v.v.','ong.','p.','p.a.','p.m.','p.o.','p.p.','p.w.','pag.','plm.','plv.','prof.','q.e.d.','q.q.','r.-k.','red.','resp.','s.j.','s.v.p.','sr.','t.a.v.','t.b.v.','t.g.v.','t.h.t.','t.h.v.','t.n.v.','t.o.v.','t.w.','t.w.v.','t.z.t.','v.','v.chr.','v.d.','v.h.','v.l.n.r.','v.r.n.l.','v.t.t.','v.v.','v.v.t.','v.w.b.','verg.','vgl.','vnl.','vnw.','voorz.','vs.','w.o.','w.v.t.t.k.','ww.','z.g.','z.g.a.n.','z.i.','z.o.z.','z.s.m.','zgn.'";
try {
database.beginTransaction();
database.execSQL(getDeleteEnglishSwordsQuery());
database.execSQL(getDeleteWordsQuery(new English().getId(), enWords));
database.execSQL(getDeleteWordsQuery(new Dutch().getId(), nlWords));
database.setTransactionSuccessful();
} catch (Exception e) {
Logger.e("Migrate to DB11", "Migration failed. " + e.getMessage());
} finally {
database.endTransaction();
}
}
};
private static String getDeleteEnglishSwordsQuery() {
return "DELETE FROM words WHERE lang=" + new English().getId() + " AND word LIKE '%''s'";
}
private static String getDeleteWordsQuery(int langId, String wordList) {
return "DELETE FROM words WHERE lang=" + langId + " AND word IN(" + wordList + ")";
}
}

View file

@ -8,12 +8,13 @@ import androidx.room.RoomDatabase;
import androidx.sqlite.db.SimpleSQLiteQuery; import androidx.sqlite.db.SimpleSQLiteQuery;
import io.github.sspanak.tt9.db.migrations.DB10; import io.github.sspanak.tt9.db.migrations.DB10;
import io.github.sspanak.tt9.db.migrations.DB11;
import io.github.sspanak.tt9.db.migrations.DB6; import io.github.sspanak.tt9.db.migrations.DB6;
import io.github.sspanak.tt9.db.migrations.DB7; import io.github.sspanak.tt9.db.migrations.DB7;
import io.github.sspanak.tt9.db.migrations.DB8; import io.github.sspanak.tt9.db.migrations.DB8;
import io.github.sspanak.tt9.db.migrations.DB9; import io.github.sspanak.tt9.db.migrations.DB9;
@Database(version = 10, entities = Word.class, exportSchema = false) @Database(version = 11, entities = Word.class, exportSchema = false)
public abstract class TT9Room extends RoomDatabase { public abstract class TT9Room extends RoomDatabase {
public abstract WordsDao wordsDao(); public abstract WordsDao wordsDao();
@ -25,7 +26,8 @@ public abstract class TT9Room extends RoomDatabase {
new DB7().getMigration(context), new DB7().getMigration(context),
DB8.MIGRATION, DB8.MIGRATION,
DB9.MIGRATION, DB9.MIGRATION,
DB10.MIGRATION DB10.MIGRATION,
DB11.MIGRATION
) )
.build(); .build();
} }
@ -41,7 +43,7 @@ public abstract class TT9Room extends RoomDatabase {
" LIMIT " + limit; " LIMIT " + limit;
if (word != null) { if (word != null) {
sql = sql.replace("WHERE 1", "WHERE 1 AND word LIKE '" + word + "%'"); sql = sql.replace("WHERE 1", "WHERE 1 AND word LIKE '" + word.replace("'", "''") + "%'");
} }
return new SimpleSQLiteQuery(sql); return new SimpleSQLiteQuery(sql);

View file

@ -18,7 +18,7 @@ public interface WordsDao {
@Query("SELECT COUNT(id) FROM words WHERE :langId < 0 OR lang = :langId") @Query("SELECT COUNT(id) FROM words WHERE :langId < 0 OR lang = :langId")
int count(int langId); int count(int langId);
@Query("DELETE FROM words WHERE LANG IN(:langIds)") @Query("DELETE FROM words WHERE lang IN(:langIds)")
void deleteByLanguage(ArrayList<Integer> langIds); void deleteByLanguage(ArrayList<Integer> langIds);
@Query("SELECT COUNT(id) FROM words WHERE lang = :langId AND word = :word") @Query("SELECT COUNT(id) FROM words WHERE lang = :langId AND word = :word")

View file

@ -262,18 +262,16 @@ public class TraditionalT9 extends KeyPadHandler {
cancelAutoAccept(); cancelAutoAccept();
forceShowWindowIfHidden(); forceShowWindowIfHidden();
String currentWord = getComposingText(); // Automatically accept the previous word, when the next one is a space or punctuation,
// Automatically accept the current word, when the next one is a space or punctuation,
// instead of requiring "OK" before that. // instead of requiring "OK" before that.
if (mInputMode.shouldAcceptCurrentSuggestion(key, hold, repeat > 0)) { // First pass, analyze the incoming key press and decide whether it could be the start of
// a new word.
if (mInputMode.shouldAcceptPreviousSuggestion(key)) {
autoCorrectSpace(acceptIncompleteSuggestion(), false, key); autoCorrectSpace(acceptIncompleteSuggestion(), false, key);
currentWord = "";
} }
// Auto-adjust the text case before each word, if the InputMode supports it. // Auto-adjust the text case before each word, if the InputMode supports it.
// We don't do it too often, because it is somewhat resource-intensive. if (getComposingText().isEmpty()) {
if (currentWord.length() == 0) {
mInputMode.determineNextWordTextCase(textField.isThereText(), textField.getTextBeforeCursor()); mInputMode.determineNextWordTextCase(textField.isThereText(), textField.getTextBeforeCursor());
} }
@ -543,11 +541,11 @@ public class TraditionalT9 extends KeyPadHandler {
} }
private void commitCurrentSuggestion(boolean entireSuggestion) { private void commitCurrentSuggestion(boolean entireSuggestion) {
if (!isSuggestionViewHidden() && currentInputConnection != null) { if (!isSuggestionViewHidden()) {
if (entireSuggestion) { if (entireSuggestion) {
textField.setComposingText(suggestionBar.getCurrentSuggestion()); textField.setComposingText(suggestionBar.getCurrentSuggestion());
} }
currentInputConnection.finishComposingText(); textField.finishComposingText();
} }
setSuggestions(null); setSuggestions(null);
@ -556,11 +554,8 @@ public class TraditionalT9 extends KeyPadHandler {
private void clearSuggestions() { private void clearSuggestions() {
setSuggestions(null); setSuggestions(null);
textField.setComposingText("");
if (currentInputConnection != null) { textField.finishComposingText();
textField.setComposingText("");
currentInputConnection.finishComposingText();
}
} }
@ -570,10 +565,22 @@ public class TraditionalT9 extends KeyPadHandler {
private void handleSuggestions() { private void handleSuggestions() {
// Automatically accept the previous word, without requiring OK. This is similar to what
// Second pass, analyze the available suggestions and decide if combining them with the
// last key press makes up a compound word like: (it)'s, (I)'ve, l'(oiseau), or it is
// just the end of a sentence, like: "word." or "another?"
if (mInputMode.shouldAcceptPreviousSuggestion()) {
String lastComposingText = getComposingText(mInputMode.getSequenceLength() - 1);
commitCurrentSuggestion(false);
mInputMode.onAcceptSuggestion(lastComposingText, true);
autoCorrectSpace(lastComposingText, false, -1);
mInputMode.determineNextWordTextCase(textField.isThereText(), textField.getTextBeforeCursor());
}
// key code "suggestions" take priority over words // key code "suggestions" take priority over words
if (mInputMode.getKeyCode() > 0) { if (mInputMode.getKeyCode() > 0) {
sendDownUpKeyEvents(mInputMode.getKeyCode()); sendDownUpKeyEvents(mInputMode.getKeyCode());
mInputMode.onAcceptSuggestion(""); mInputMode.reset();
return; return;
} }
@ -605,16 +612,27 @@ public class TraditionalT9 extends KeyPadHandler {
} }
private String getComposingText() { private String getComposingText(int maxLength) {
if (maxLength == 0) {
return "";
}
maxLength = maxLength > 0 ? Math.min(maxLength, mInputMode.getSequenceLength()) : mInputMode.getSequenceLength();
String text = suggestionBar.getCurrentSuggestion(); String text = suggestionBar.getCurrentSuggestion();
if (text.length() > 0 && text.length() > mInputMode.getSequenceLength()) { if (text.length() > 0 && text.length() > maxLength) {
text = text.substring(0, mInputMode.getSequenceLength()); text = text.substring(0, maxLength);
} }
return text; return text;
} }
private String getComposingText() {
return getComposingText(-1);
}
private void refreshComposingText() { private void refreshComposingText() {
textField.setComposingText(getComposingText()); textField.setComposingText(getComposingText());
} }
@ -729,11 +747,11 @@ public class TraditionalT9 extends KeyPadHandler {
private void showAddWord() { private void showAddWord() {
if (currentInputConnection == null) { if (shouldBeOff()) {
return; return;
} }
currentInputConnection.finishComposingText(); textField.finishComposingText();
clearSuggestions(); clearSuggestions();
UI.showAddWordDialog(this, mLanguage.getId(), textField.getSurroundingWord()); UI.showAddWordDialog(this, mLanguage.getId(), textField.getSurroundingWord());

View file

@ -56,7 +56,8 @@ abstract public class InputMode {
abstract public boolean onOtherKey(int key); abstract public boolean onOtherKey(int key);
// Suggestions // Suggestions
public void onAcceptSuggestion(@NonNull String suggestion) {} public void onAcceptSuggestion(@NonNull String word) { onAcceptSuggestion(word, false); }
public void onAcceptSuggestion(@NonNull String word, boolean preserveWordList) {}
/** /**
* loadSuggestions * loadSuggestions
@ -97,7 +98,8 @@ abstract public class InputMode {
} }
// Interaction with the IME. Return "true" if it should perform the respective action. // Interaction with the IME. Return "true" if it should perform the respective action.
public boolean shouldAcceptCurrentSuggestion(int key, boolean hold, boolean repeat) { return false; } public boolean shouldAcceptPreviousSuggestion() { return false; }
public boolean shouldAcceptPreviousSuggestion(int nextKey) { return false; }
public boolean shouldAddAutoSpace(InputType inputType, TextField textField, boolean isWordAcceptedManually, int nextKey) { return false; } public boolean shouldAddAutoSpace(InputType inputType, TextField textField, boolean isWordAcceptedManually, int nextKey) { return false; }
public boolean shouldDeletePrecedingSpace(InputType inputType) { return false; } public boolean shouldDeletePrecedingSpace(InputType inputType) { return false; }
public boolean shouldSelectNextSuggestion() { return false; } public boolean shouldSelectNextSuggestion() { return false; }

View file

@ -70,7 +70,7 @@ public class ModeABC extends InputMode {
@Override final public boolean isABC() { return true; } @Override final public boolean isABC() { return true; }
@Override public int getSequenceLength() { return 1; } @Override public int getSequenceLength() { return 1; }
@Override public boolean shouldAcceptCurrentSuggestion(int key, boolean hold, boolean repeat) { return hold || !repeat; } @Override public boolean shouldAcceptPreviousSuggestion() { return autoAcceptTimeout == 0 || !shouldSelectNextLetter; }
@Override public boolean shouldTrackUpDown() { return true; } @Override public boolean shouldTrackUpDown() { return true; }
@Override public boolean shouldTrackLeftRight() { return true; } @Override public boolean shouldTrackLeftRight() { return true; }
@Override public boolean shouldSelectNextSuggestion() { @Override public boolean shouldSelectNextSuggestion() {

View file

@ -2,7 +2,10 @@ package io.github.sspanak.tt9.ime.modes;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import java.util.ArrayList;
import io.github.sspanak.tt9.Logger; import io.github.sspanak.tt9.Logger;
import io.github.sspanak.tt9.TextTools;
import io.github.sspanak.tt9.db.DictionaryDb; import io.github.sspanak.tt9.db.DictionaryDb;
import io.github.sspanak.tt9.ime.helpers.InputType; import io.github.sspanak.tt9.ime.helpers.InputType;
import io.github.sspanak.tt9.ime.helpers.TextField; import io.github.sspanak.tt9.ime.helpers.TextField;
@ -19,7 +22,6 @@ public class ModePredictive extends InputMode {
private String digitSequence = ""; private String digitSequence = "";
private String lastAcceptedWord = ""; private String lastAcceptedWord = "";
private String lastAcceptedSequence = "";
// stem filter // stem filter
private boolean isStemFuzzy = false; private boolean isStemFuzzy = false;
@ -123,6 +125,31 @@ public class ModePredictive extends InputMode {
} }
/**
* clearLastAcceptedWord
* Removes the last accepted word from the suggestions list and the "digitSequence"
* or stops silently, when there is nothing to do.
*/
private void clearLastAcceptedWord() {
if (
lastAcceptedWord.isEmpty()
|| suggestions.isEmpty()
|| !suggestions.get(0).toLowerCase(language.getLocale()).startsWith(lastAcceptedWord.toLowerCase(language.getLocale()))
) {
return;
}
int lastAcceptedWordLength = lastAcceptedWord.length();
digitSequence = digitSequence.length() > lastAcceptedWordLength ? digitSequence.substring(lastAcceptedWordLength) : "";
ArrayList<String> lastSuggestions = new ArrayList<>(suggestions);
suggestions.clear();
for (String s : lastSuggestions) {
suggestions.add(s.length() >= lastAcceptedWordLength ? s.substring(lastAcceptedWordLength) : "");
}
}
/** /**
* clearWordStem * clearWordStem
* Do not filter the suggestions by the word set using "setWordStem()", use only the digit sequence. * Do not filter the suggestions by the word set using "setWordStem()", use only the digit sequence.
@ -156,15 +183,18 @@ public class ModePredictive extends InputMode {
* Note that you need to manually get the suggestions again to obtain a filtered list. * Note that you need to manually get the suggestions again to obtain a filtered list.
*/ */
@Override @Override
public boolean setWordStem(String wordStem, boolean exact) { public boolean setWordStem(String newStem, boolean exact) {
if (language == null || wordStem == null || wordStem.length() < 1) { String sanitizedStem = TextTools.removeNonLetters(newStem);
if (language == null || sanitizedStem == null || sanitizedStem.length() < 1) {
return false; return false;
} }
try { try {
digitSequence = language.getDigitSequenceForWord(wordStem); // digitSequence = "the raw input", so that everything the user typed is preserved visually
// stem = "the sanitized input", because filtering by anything that is not a letter makes no sense
digitSequence = language.getDigitSequenceForWord(newStem);
stem = sanitizedStem.toLowerCase(language.getLocale());
isStemFuzzy = !exact; isStemFuzzy = !exact;
stem = digitSequence.startsWith("0") || digitSequence.startsWith("1") ? "" : wordStem.toLowerCase(language.getLocale());
Logger.d("tt9/setWordStem", "Stem is now: " + stem + (isStemFuzzy ? " (fuzzy)" : "")); Logger.d("tt9/setWordStem", "Stem is now: " + stem + (isStemFuzzy ? " (fuzzy)" : ""));
return true; return true;
@ -172,7 +202,7 @@ public class ModePredictive extends InputMode {
isStemFuzzy = false; isStemFuzzy = false;
stem = ""; stem = "";
Logger.w("tt9/setWordStem", "Ignoring invalid stem: " + wordStem + ". " + e.getMessage()); Logger.w("tt9/setWordStem", "Ignoring invalid stem: " + newStem + ". " + e.getMessage());
return false; return false;
} }
} }
@ -239,19 +269,26 @@ public class ModePredictive extends InputMode {
/** /**
* onAcceptSuggestion * onAcceptSuggestion
* Bring this word up in the suggestions list next time. * Bring this word up in the suggestions list next time and if necessary preserves the suggestion list
* with "currentWord" cleaned from them.
*/ */
@Override @Override
public void onAcceptSuggestion(@NonNull String currentWord) { public void onAcceptSuggestion(@NonNull String currentWord, boolean preserveWords) {
lastAcceptedWord = currentWord; lastAcceptedWord = currentWord;
lastAcceptedSequence = digitSequence;
reset();
if (currentWord.length() == 0) { if (preserveWords) {
clearLastAcceptedWord();
} else {
reset();
}
stem = "";
if (currentWord.isEmpty()) {
Logger.i("acceptCurrentSuggestion", "Current word is empty. Nothing to accept."); Logger.i("acceptCurrentSuggestion", "Current word is empty. Nothing to accept.");
return; return;
} }
// increment the frequency of the given word
try { try {
String sequence = language.getDigitSequenceForWord(currentWord); String sequence = language.getDigitSequenceForWord(currentWord);
@ -284,22 +321,34 @@ public class ModePredictive extends InputMode {
/** /**
* shouldAcceptCurrentSuggestion * shouldAcceptPreviousSuggestion
* In this mode, In addition to confirming the suggestion in the input field, * In this mode, In addition to confirming the suggestion in the input field,
* we also increase its' priority. This function determines whether we want to do all this or not. * we also increase its' priority. This function determines whether we want to do all this or not.
*/ */
@Override @Override
public boolean shouldAcceptCurrentSuggestion(int key, boolean hold, boolean repeat) { public boolean shouldAcceptPreviousSuggestion(int nextKey) {
return return
hold !digitSequence.isEmpty() && (
// Quickly accept suggestions using "space" instead of pressing "ok" then "space" (nextKey == 0 && digitSequence.charAt(digitSequence.length() - 1) != '0')
|| (key == 0 && !repeat) || (nextKey != 0 && digitSequence.charAt(digitSequence.length() - 1) == '0')
// Punctuation is considered "a word", so that we can increase the priority as needed );
// Also, it must break the current word. }
|| (!language.isPunctuationPartOfWords() && key == 1 && digitSequence.length() > 0 && !digitSequence.endsWith("1"))
// On the other hand, letters also "break" punctuation.
|| (!language.isPunctuationPartOfWords() && key != 1 && digitSequence.endsWith("1")) /**
|| (digitSequence.endsWith("0") && key != 0); * shouldAcceptPreviousSuggestion
* Variant for post suggestion load analysis.
*/
@Override
public boolean shouldAcceptPreviousSuggestion() {
return
(autoAcceptTimeout == 0 && !digitSequence.startsWith("0"))
|| (
!digitSequence.isEmpty()
&& !predictions.areThereDbWords()
&& digitSequence.contains("1")
&& TextTools.containsOtherThan1(digitSequence)
);
} }
@ -307,11 +356,10 @@ public class ModePredictive extends InputMode {
public boolean shouldAddAutoSpace(InputType inputType, TextField textField, boolean isWordAcceptedManually, int nextKey) { public boolean shouldAddAutoSpace(InputType inputType, TextField textField, boolean isWordAcceptedManually, int nextKey) {
return autoSpace return autoSpace
.setLastWord(lastAcceptedWord) .setLastWord(lastAcceptedWord)
.setLastSequence(lastAcceptedSequence) .setLastSequence()
.setInputType(inputType) .setInputType(inputType)
.setTextField(textField) .setTextField(textField)
.shouldAddAutoSpace(isWordAcceptedManually, nextKey); .shouldAddAutoSpace(isWordAcceptedManually, nextKey);
} }
@ -319,7 +367,6 @@ public class ModePredictive extends InputMode {
public boolean shouldDeletePrecedingSpace(InputType inputType) { public boolean shouldDeletePrecedingSpace(InputType inputType) {
return autoSpace return autoSpace
.setLastWord(lastAcceptedWord) .setLastWord(lastAcceptedWord)
.setLastSequence(lastAcceptedSequence)
.setInputType(inputType) .setInputType(inputType)
.setTextField(null) .setTextField(null)
.shouldDeletePrecedingSpace(); .shouldDeletePrecedingSpace();

View file

@ -1,22 +1,16 @@
package io.github.sspanak.tt9.ime.modes.helpers; package io.github.sspanak.tt9.ime.modes.helpers;
import java.util.regex.Pattern; import io.github.sspanak.tt9.TextTools;
import io.github.sspanak.tt9.ime.helpers.InputType; import io.github.sspanak.tt9.ime.helpers.InputType;
import io.github.sspanak.tt9.ime.helpers.TextField; import io.github.sspanak.tt9.ime.helpers.TextField;
import io.github.sspanak.tt9.preferences.SettingsStore; import io.github.sspanak.tt9.preferences.SettingsStore;
public class AutoSpace { public class AutoSpace {
private final Pattern isNumber = Pattern.compile("\\s*\\d+\\s*");
private final Pattern nextIsLetter = Pattern.compile("^\\p{L}+");
private final Pattern nextIsPunctuation = Pattern.compile("^\\p{Punct}");
private final SettingsStore settings; private final SettingsStore settings;
private InputType inputType; private InputType inputType;
private TextField textField; private TextField textField;
private String lastWord; private String lastWord;
private String lastSequence;
public AutoSpace(SettingsStore settingsStore) { public AutoSpace(SettingsStore settingsStore) {
settings = settingsStore; settings = settingsStore;
@ -37,8 +31,7 @@ public class AutoSpace {
return this; return this;
} }
public AutoSpace setLastSequence(String lastSequence) { public AutoSpace setLastSequence() {
this.lastSequence = lastSequence;
return this; return this;
} }
@ -57,12 +50,11 @@ public class AutoSpace {
return return
settings.getAutoSpace() settings.getAutoSpace()
&& !inputType.isSpecialized() && !inputType.isSpecialized()
&& !nextChars.startsWith(" ") && nextKey != 0
&& !isNumber.matcher(previousChars).find() && !TextTools.startsWithWhitespace(nextChars)
&& !nextIsPunctuation.matcher(nextChars).find()
&& ( && (
shouldAddAfterPunctuation(previousChars, nextKey) shouldAddAfterWord(isWordAcceptedManually, previousChars, nextChars, nextKey)
|| shouldAddAfterWord(isWordAcceptedManually, nextChars) || shouldAddAfterPunctuation(previousChars, nextChars, nextKey)
); );
} }
@ -73,24 +65,23 @@ public class AutoSpace {
* The rules are similar to the ones in the standard Android keyboard (with some exceptions, * The rules are similar to the ones in the standard Android keyboard (with some exceptions,
* because we are not using a QWERTY keyboard here). * because we are not using a QWERTY keyboard here).
*/ */
private boolean shouldAddAfterPunctuation(String previousChars, int nextKey) { private boolean shouldAddAfterPunctuation(String previousChars, String nextChars, int nextKey) {
return char previousChar = previousChars.isEmpty() ? 0 : previousChars.charAt(previousChars.length() - 1);
// no space after whitespace or special characters
!previousChars.endsWith(" ") && !previousChars.endsWith("\n") && !previousChars.endsWith("\t") // previous whitespace
&& !lastSequence.equals("0") // previous previous math/special char
&& nextKey != 0 // composing (upcoming) whitespace or special character
// add space after the these return
nextKey != 1
&& !TextTools.nextIsPunctuation(nextChars)
&& !TextTools.startsWithNumber(nextChars)
&& ( && (
previousChars.endsWith(".") previousChar == '.'
|| previousChars.endsWith(",") || previousChar == ','
|| previousChars.endsWith(";") || previousChar == ';'
|| previousChars.endsWith(":") || previousChar == ':'
|| previousChars.endsWith("!") || previousChar == '!'
|| previousChars.endsWith("?") || previousChar == '?'
|| previousChars.endsWith(")") || previousChar == ')'
|| previousChars.endsWith("]") || previousChar == ']'
|| previousChars.endsWith("%") || previousChar == '%'
|| previousChars.endsWith(" -") || previousChars.endsWith(" -")
|| previousChars.endsWith(" /") || previousChars.endsWith(" /")
); );
@ -98,15 +89,15 @@ public class AutoSpace {
/** /**
* shouldAddAfterPunctuation * shouldAddAfterWord
* Similar to "shouldAddAfterPunctuation()", but determines whether to add a space after words. * Similar to "shouldAddAfterPunctuation()", but determines whether to add a space after words.
*/ */
private boolean shouldAddAfterWord(boolean isWordAcceptedManually, String nextChars) { private boolean shouldAddAfterWord(boolean isWordAcceptedManually, String previousChars, String nextChars, int nextKey) {
return return
// Do not add space when auto-accepting words, because it feels very confusing when typing. isWordAcceptedManually // Do not add space when auto-accepting words, because it feels very confusing when typing.
isWordAcceptedManually && nextKey != 1
// Right before another word && nextChars.isEmpty()
&& !nextIsLetter.matcher(nextChars).find(); && TextTools.previousIsLetter(previousChars);
} }

View file

@ -1,14 +1,11 @@
package io.github.sspanak.tt9.ime.modes.helpers; package io.github.sspanak.tt9.ime.modes.helpers;
import java.util.regex.Pattern; import io.github.sspanak.tt9.TextTools;
import io.github.sspanak.tt9.ime.modes.InputMode; import io.github.sspanak.tt9.ime.modes.InputMode;
import io.github.sspanak.tt9.languages.Language; import io.github.sspanak.tt9.languages.Language;
import io.github.sspanak.tt9.preferences.SettingsStore; import io.github.sspanak.tt9.preferences.SettingsStore;
public class AutoTextCase { public class AutoTextCase {
private final Pattern nextToWordRegex = Pattern.compile("\\b$");
private final Pattern startOfSentenceRegex = Pattern.compile("(?<!\\.)(^|[.?!¿¡])\\s*$");
private final SettingsStore settings; private final SettingsStore settings;
@ -68,11 +65,11 @@ public class AutoTextCase {
} }
// start of sentence, excluding after "..." // start of sentence, excluding after "..."
if (startOfSentenceRegex.matcher(textBeforeCursor).find()) { if (TextTools.isStartOfSentence(textBeforeCursor)) {
return InputMode.CASE_CAPITALIZE; return InputMode.CASE_CAPITALIZE;
} }
if (nextToWordRegex.matcher(textBeforeCursor).find()) { if (TextTools.isNextToWord(textBeforeCursor)) {
return InputMode.CASE_LOWER; return InputMode.CASE_LOWER;
} }

View file

@ -23,6 +23,7 @@ public class Predictions {
private Runnable onWordsChanged = () -> {}; private Runnable onWordsChanged = () -> {};
// data // data
private boolean areThereDbWords = false;
private final ArrayList<String> words = new ArrayList<>(); private final ArrayList<String> words = new ArrayList<>();
// punctuation/emoji // punctuation/emoji
@ -82,6 +83,10 @@ public class Predictions {
return words; return words;
} }
public boolean areThereDbWords() {
return areThereDbWords;
}
/** /**
* suggestStem * suggestStem
@ -89,7 +94,7 @@ public class Predictions {
* the user has pressed X keys (otherwise, it makes no sense to add it). * the user has pressed X keys (otherwise, it makes no sense to add it).
*/ */
private void suggestStem() { private void suggestStem() {
if (stem.length() > 0 && stem.length() == digitSequence.length()) { if (!stem.isEmpty() && stem.length() == digitSequence.length()) {
words.add(stem); words.add(stem);
} }
} }
@ -114,7 +119,7 @@ public class Predictions {
* sequence or loads the static ones. * sequence or loads the static ones.
*/ */
public void load() { public void load() {
if (digitSequence == null || digitSequence.length() == 0) { if (digitSequence == null || digitSequence.isEmpty()) {
words.clear(); words.clear();
onWordsChanged.run(); onWordsChanged.run();
return; return;
@ -124,7 +129,7 @@ public class Predictions {
onWordsChanged.run(); onWordsChanged.run();
} else { } else {
DictionaryDb.getWords( DictionaryDb.getWords(
this::onDbWords, (words) -> onDbWords(words, true),
language, language,
digitSequence, digitSequence,
stem, stem,
@ -170,6 +175,23 @@ public class Predictions {
return true; return true;
} }
private void loadWithoutLeadingPunctuation() {
DictionaryDb.getWords(
(dbWords) -> {
char firstChar = inputWord.charAt(0);
for (int i = 0; i < dbWords.size(); i++) {
dbWords.set(i, firstChar + dbWords.get(i));
}
onDbWords(dbWords, false);
},
language,
digitSequence.substring(1),
stem.length() > 1 ? stem.substring(1) : "",
settings.getSuggestionsMin(),
settings.getSuggestionsMax()
);
}
/** /**
* dbWordsHandler * dbWordsHandler
@ -177,8 +199,18 @@ public class Predictions {
* they will be generated based on the "inputWord". After the word list is compiled, it notifies the * they will be generated based on the "inputWord". After the word list is compiled, it notifies the
* external handler it is now possible to use it with "getList()". * external handler it is now possible to use it with "getList()".
*/ */
private void onDbWords (ArrayList<String> dbWords) { private void onDbWords(ArrayList<String> dbWords, boolean isRetryAllowed) {
if (dbWords.size() == 0 && digitSequence.length() > 0) { // only the first round matters, the second one is just for getting the letters for a given key
areThereDbWords = !dbWords.isEmpty() && isRetryAllowed;
// If there were no database words for ",a", try getting the letters only (e.g. "a", "b", "c").
// We do this to display them in the correct order.
if (dbWords.isEmpty() && isRetryAllowed && digitSequence.length() == 2 && digitSequence.charAt(0) == '1') {
loadWithoutLeadingPunctuation();
return;
}
if (dbWords.isEmpty() && !digitSequence.isEmpty()) {
emptyDbWarning.emitOnce(language); emptyDbWarning.emitOnce(language);
dbWords = generatePossibleCompletions(inputWord); dbWords = generatePossibleCompletions(inputWord);
} }
@ -186,7 +218,7 @@ public class Predictions {
words.clear(); words.clear();
suggestStem(); suggestStem();
suggestMissingWords(generatePossibleStemVariations(dbWords)); suggestMissingWords(generatePossibleStemVariations(dbWords));
suggestMissingWords(dbWords); suggestMissingWords(insertPunctuationCompletions(dbWords));
onWordsChanged.run(); onWordsChanged.run();
} }
@ -206,20 +238,16 @@ public class Predictions {
// Make sure the displayed word and the digit sequence, we will be generating suggestions from, // Make sure the displayed word and the digit sequence, we will be generating suggestions from,
// have the same length, to prevent visual discrepancies. // have the same length, to prevent visual discrepancies.
baseWord = (baseWord != null && baseWord.length() > 0) ? baseWord.substring(0, Math.min(digitSequence.length() - 1, baseWord.length())) : ""; baseWord = (baseWord != null && !baseWord.isEmpty()) ? baseWord.substring(0, Math.min(digitSequence.length() - 1, baseWord.length())) : "";
// append all letters for the last digit in the sequence (the last pressed key) // append all letters for the last digit in the sequence (the last pressed key)
int lastSequenceDigit = digitSequence.charAt(digitSequence.length() - 1) - '0'; int lastSequenceDigit = digitSequence.charAt(digitSequence.length() - 1) - '0';
for (String keyLetter : language.getKeyCharacters(lastSequenceDigit)) { for (String keyLetter : language.getKeyCharacters(lastSequenceDigit, false)) {
// let's skip numbers, because it's weird, for example: generatedWords.add(baseWord + keyLetter);
// | weird | weire | weirf | weir2 |
if (keyLetter.charAt(0) < '0' || keyLetter.charAt(0) > '9') {
generatedWords.add(baseWord + keyLetter);
}
} }
// if there are no letters for this key, just append the number // if there are no letters for this key, just append the number
if (generatedWords.size() == 0) { if (generatedWords.isEmpty()) {
generatedWords.add(baseWord + digitSequence.charAt(digitSequence.length() - 1)); generatedWords.add(baseWord + digitSequence.charAt(digitSequence.length() - 1));
} }
@ -227,6 +255,46 @@ public class Predictions {
} }
/**
* insertPunctuationCompletions
* When given: "you'", for example, this also generates all other 1-key alternatives, like:
* "you.", "you?", "you!" and so on. The generated words will be inserted after the direct
* database matches and before the fuzzy matches, as if they were direct matches with low frequency.
* This is to preserve the sorting by length and frequency.
*/
private ArrayList<String> insertPunctuationCompletions(ArrayList<String> dbWords) {
if (!stem.isEmpty() || dbWords.isEmpty() || digitSequence.length() < 2 || !digitSequence.endsWith("1")) {
return dbWords;
}
ArrayList<String> complementedWords = new ArrayList<>();
int exactMatchLength = digitSequence.length();
// shortest database words (exact matches)
for (String w : dbWords) {
if (w.length() <= exactMatchLength) {
complementedWords.add(w);
}
}
// generated "exact matches"
for (String w : generatePossibleCompletions(dbWords.get(0))) {
if (!dbWords.contains(w) && !dbWords.contains(w.toLowerCase(language.getLocale()))) {
complementedWords.add(w);
}
}
// longer database words (fuzzy matches)
for (String w : dbWords) {
if (w.length() > exactMatchLength) {
complementedWords.add(w);
}
}
return complementedWords;
}
/** /**
* generatePossibleStemVariations * generatePossibleStemVariations
* Similar to generatePossibleCompletions(), but uses the current filter as a base word. This is * Similar to generatePossibleCompletions(), but uses the current filter as a base word. This is
@ -242,7 +310,7 @@ public class Predictions {
*/ */
private ArrayList<String> generatePossibleStemVariations(ArrayList<String> dbWords) { private ArrayList<String> generatePossibleStemVariations(ArrayList<String> dbWords) {
ArrayList<String> variations = new ArrayList<>(); ArrayList<String> variations = new ArrayList<>();
if (stem.length() == 0) { if (stem.isEmpty()) {
return variations; return variations;
} }

View file

@ -18,7 +18,6 @@ public class Language {
// settings // settings
protected boolean hasUpperCase = true; protected boolean hasUpperCase = true;
protected boolean isPunctuationPartOfWords; // see the getter for more info
final public int getId() { final public int getId() {
if (id == 0) { if (id == 0) {
@ -60,24 +59,6 @@ public class Language {
return abcString; return abcString;
} }
/**
* isPunctuationPartOfWords
* This plays a role in Predictive mode only.
*
* Return "true", if you need to use the 1-key for typing words, such as:
* "it's" (English), "a'tje" (Dutch), "п'ят" (Ukrainian).
*
* Return "false" also:
* - hide words like the above from the suggestions.
* - 1-key would commit the current word, then display the punctuation list.
* For example, pressing 1-key after "it" would accept "it" as a separate word,
* then display only: | , | . | ! | ? | ...
*
* "false" is recommended when apostrophes or other punctuation are not part of the words,
* because it would allow faster typing.
*/
final public boolean isPunctuationPartOfWords() { return isPunctuationPartOfWords; }
public boolean hasUpperCase() { public boolean hasUpperCase() {
return hasUpperCase; return hasUpperCase;
@ -124,7 +105,21 @@ public class Language {
} }
public String capitalize(String word) { public String capitalize(String word) {
return word != null ? word.substring(0, 1).toUpperCase(locale) + word.substring(1).toLowerCase(locale) : null; if (word == null) {
return null;
}
String capitalizedWord = "";
if (!word.isEmpty()) {
capitalizedWord += word.substring(0, 1).toUpperCase(locale);
}
if (word.length() > 1) {
capitalizedWord += word.substring(1).toLowerCase(locale);
}
return capitalizedWord;
} }
public boolean isMixedCaseWord(String word) { public boolean isMixedCaseWord(String word) {

View file

@ -11,8 +11,6 @@ public class BrazilianPortuguese extends English {
locale = new Locale("pt","BR"); locale = new Locale("pt","BR");
dictionaryFile = "pt-BR-utf8.csv"; dictionaryFile = "pt-BR-utf8.csv";
isPunctuationPartOfWords = true;
characterMap.get(2).addAll(Arrays.asList("ç", "á", "â", "ã", "à")); characterMap.get(2).addAll(Arrays.asList("ç", "á", "â", "ã", "à"));
characterMap.get(3).addAll(Arrays.asList("é", "ê", "è")); characterMap.get(3).addAll(Arrays.asList("é", "ê", "è"));
characterMap.get(4).add("í"); characterMap.get(4).add("í");

View file

@ -12,8 +12,6 @@ public class Bulgarian extends Language {
locale = new Locale("bg","BG"); locale = new Locale("bg","BG");
dictionaryFile = "bg-utf8.csv"; dictionaryFile = "bg-utf8.csv";
isPunctuationPartOfWords = false;
characterMap = new ArrayList<>(Arrays.asList( characterMap = new ArrayList<>(Arrays.asList(
Characters.Special, // 0 Characters.Special, // 0
Characters.Sentence, // 1 Characters.Sentence, // 1

View file

@ -10,8 +10,6 @@ public class Dutch extends English {
locale = new Locale("nl","NL"); locale = new Locale("nl","NL");
dictionaryFile = "nl-utf8.csv"; dictionaryFile = "nl-utf8.csv";
isPunctuationPartOfWords = true;
characterMap.get(2).addAll(Arrays.asList("à", "ä", "ç")); characterMap.get(2).addAll(Arrays.asList("à", "ä", "ç"));
characterMap.get(3).addAll(Arrays.asList("é", "è", "ê", "ë")); characterMap.get(3).addAll(Arrays.asList("é", "è", "ê", "ë"));
characterMap.get(4).addAll(Arrays.asList("î", "ï")); characterMap.get(4).addAll(Arrays.asList("î", "ï"));

View file

@ -12,8 +12,6 @@ public class English extends Language {
locale = Locale.ENGLISH; locale = Locale.ENGLISH;
dictionaryFile = "en-utf8.csv"; dictionaryFile = "en-utf8.csv";
isPunctuationPartOfWords = true;
characterMap = new ArrayList<>(Arrays.asList( characterMap = new ArrayList<>(Arrays.asList(
Characters.Special, // 0 Characters.Special, // 0
Characters.Sentence, // 1 Characters.Sentence, // 1

View file

@ -10,8 +10,6 @@ public class Finnish extends English {
locale = new Locale("fi","FI"); locale = new Locale("fi","FI");
dictionaryFile = "fi-utf8.csv"; dictionaryFile = "fi-utf8.csv";
isPunctuationPartOfWords = true;
characterMap.get(2).addAll(Arrays.asList("ä", "å")); characterMap.get(2).addAll(Arrays.asList("ä", "å"));
characterMap.get(6).add("ö"); characterMap.get(6).add("ö");
} }

View file

@ -10,8 +10,6 @@ public class French extends English {
locale = Locale.FRENCH; locale = Locale.FRENCH;
dictionaryFile = "fr-utf8.csv"; dictionaryFile = "fr-utf8.csv";
isPunctuationPartOfWords = false;
characterMap.get(2).addAll(Arrays.asList("à", "â", "æ", "ç")); characterMap.get(2).addAll(Arrays.asList("à", "â", "æ", "ç"));
characterMap.get(3).addAll(Arrays.asList("é", "è", "ê", "ë")); characterMap.get(3).addAll(Arrays.asList("é", "è", "ê", "ë"));
characterMap.get(4).addAll(Arrays.asList("î", "ï")); characterMap.get(4).addAll(Arrays.asList("î", "ï"));

View file

@ -9,8 +9,6 @@ public class German extends English {
locale = Locale.GERMAN; locale = Locale.GERMAN;
dictionaryFile = "de-utf8.csv"; dictionaryFile = "de-utf8.csv";
isPunctuationPartOfWords = false;
characterMap.get(2).add("ä"); characterMap.get(2).add("ä");
characterMap.get(6).add("ö"); characterMap.get(6).add("ö");
characterMap.get(7).add("ß"); characterMap.get(7).add("ß");

View file

@ -14,7 +14,6 @@ public class Hebrew extends Language {
abcString = "אבג"; abcString = "אבג";
hasUpperCase = false; hasUpperCase = false;
isPunctuationPartOfWords = true;
characterMap = new ArrayList<>(Arrays.asList( characterMap = new ArrayList<>(Arrays.asList(
Characters.Special, // 0 Characters.Special, // 0

View file

@ -10,8 +10,6 @@ public class Italian extends English {
locale = Locale.ITALIAN; locale = Locale.ITALIAN;
dictionaryFile = "it-utf8.csv"; dictionaryFile = "it-utf8.csv";
isPunctuationPartOfWords = false;
characterMap.get(2).add("à"); characterMap.get(2).add("à");
characterMap.get(3).addAll(Arrays.asList("é", "è")); characterMap.get(3).addAll(Arrays.asList("é", "è"));
characterMap.get(4).addAll(Arrays.asList("ì", "í", "î")); characterMap.get(4).addAll(Arrays.asList("ì", "í", "î"));

View file

@ -10,8 +10,6 @@ public class Norwegian extends English {
locale = new Locale("nb","NO"); locale = new Locale("nb","NO");
dictionaryFile = "nb-utf8.csv"; dictionaryFile = "nb-utf8.csv";
isPunctuationPartOfWords = false;
characterMap.get(2).addAll(Arrays.asList("æ", "å")); characterMap.get(2).addAll(Arrays.asList("æ", "å"));
characterMap.get(3).addAll(Arrays.asList("é", "è")); characterMap.get(3).addAll(Arrays.asList("é", "è"));
characterMap.get(6).addAll(Arrays.asList("ø", "ó", "ò", "ô")); characterMap.get(6).addAll(Arrays.asList("ø", "ó", "ò", "ô"));

View file

@ -10,8 +10,6 @@ public class Polish extends English {
locale = new Locale("pl","PL"); locale = new Locale("pl","PL");
dictionaryFile = "pl-utf8.csv"; dictionaryFile = "pl-utf8.csv";
isPunctuationPartOfWords = false;
characterMap.get(2).addAll(Arrays.asList("ą", "ć")); characterMap.get(2).addAll(Arrays.asList("ą", "ć"));
characterMap.get(3).add("ę"); characterMap.get(3).add("ę");
characterMap.get(5).add("ł"); characterMap.get(5).add("ł");

View file

@ -12,8 +12,6 @@ public class Russian extends Language {
locale = new Locale("ru","RU"); locale = new Locale("ru","RU");
dictionaryFile = "ru-utf8.csv"; dictionaryFile = "ru-utf8.csv";
isPunctuationPartOfWords = false;
characterMap = new ArrayList<>(Arrays.asList( characterMap = new ArrayList<>(Arrays.asList(
Characters.Special, // 0 Characters.Special, // 0
Characters.Sentence, // 1 Characters.Sentence, // 1

View file

@ -13,8 +13,6 @@ public class Spanish extends English {
locale = new Locale("es", "ES"); locale = new Locale("es", "ES");
dictionaryFile = "es-utf8.csv"; dictionaryFile = "es-utf8.csv";
isPunctuationPartOfWords = false;
characterMap.set(1, new ArrayList<>(Characters.Sentence)); characterMap.set(1, new ArrayList<>(Characters.Sentence));
characterMap.get(1).addAll(Arrays.asList("¡", "¿")); characterMap.get(1).addAll(Arrays.asList("¡", "¿"));

View file

@ -10,8 +10,6 @@ public class Swedish extends English {
locale = new Locale("sv","SE"); locale = new Locale("sv","SE");
dictionaryFile = "sv-utf8.csv"; dictionaryFile = "sv-utf8.csv";
isPunctuationPartOfWords = false;
characterMap.get(2).addAll(Arrays.asList("å", "ä")); characterMap.get(2).addAll(Arrays.asList("å", "ä"));
characterMap.get(3).add("é"); characterMap.get(3).add("é");
characterMap.get(6).add("ö"); characterMap.get(6).add("ö");

View file

@ -12,8 +12,6 @@ public class Ukrainian extends Language {
locale = new Locale("uk","UA"); locale = new Locale("uk","UA");
dictionaryFile = "uk-utf8.csv"; dictionaryFile = "uk-utf8.csv";
isPunctuationPartOfWords = true;
characterMap = new ArrayList<>(Arrays.asList( characterMap = new ArrayList<>(Arrays.asList(
Characters.Special, // 0 Characters.Special, // 0
Characters.Sentence, // 1 Characters.Sentence, // 1

View file

@ -8,6 +8,5 @@ public class Yiddish extends Hebrew {
locale = new Locale("ji","JI"); locale = new Locale("ji","JI");
dictionaryFile = "ji-utf8.csv"; dictionaryFile = "ji-utf8.csv";
isPunctuationPartOfWords = true;
} }
} }