1
0
Fork 0

Arabic Language

fixed custom ABC string not being displayed

simplified the Arabic numbers code

simplified displaying the Arabic question mark on the virtual keyboard

Arabic numbers are properly displayed on the virtual keyboard

injected word frequencies and sorted the dictionary

updated the readme
This commit is contained in:
Arabi12321 2024-01-08 22:27:00 -06:00 committed by Dimo Karaivanov
parent ec87ce080c
commit 79902e4e95
15 changed files with 1272521 additions and 26 deletions

View file

@ -0,0 +1,7 @@
Arabic word list by: Amchart Jamal
Version: 90ff427 (2020-10-29)
Source: https://github.com/jamalamch/Arabic-Words/blob/master/AllListWordArabic.txt
Frequency list by: AnySoftKeyboard
Version: 082f145 (2020-01-29)
Source: https://github.com/AnySoftKeyboard/AnySoftKeyboard/blob/main/addons/languages/arabic/pack/dictionary/lulua.combined.gz

View file

@ -0,0 +1,16 @@
---
locale: ar-JO
dictionaryFile: ar-utf8.csv
abcString: أﺏﺕ
hasUpperCase: no
layout:
- [SPECIAL] # 0
- [PUNCTUATION_AR] # 1
- [ب,ت,ة,ث] # 2
- [ا,أ,إ,آ,ى,ؤ,ئ,ء] # 3
- [س,ش,ص,ض] # 4
- [د,ذ,ر,ز] # 5
- [ج,ح,خ] # 6
- [ن,ه,و,ي] # 7
- [ف,ق,ك,ل,م] # 8
- [ط,ظ,ع,غ] # 9

File diff suppressed because it is too large Load diff

View file

@ -11,7 +11,7 @@ public class TextTools {
private static final Pattern previousIsLetter = Pattern.compile("\\p{L}$"); private static final Pattern previousIsLetter = Pattern.compile("\\p{L}$");
private static final Pattern nextIsPunctuation = Pattern.compile("^\\p{Punct}"); private static final Pattern nextIsPunctuation = Pattern.compile("^\\p{Punct}");
private static final Pattern nextToWord = Pattern.compile("\\b$"); private static final Pattern nextToWord = Pattern.compile("\\b$");
private static final Pattern startOfSentence = Pattern.compile("(?<!\\.)(^|[.?!¿¡])\\s+$"); private static final Pattern startOfSentence = Pattern.compile("(?<!\\.)(^|[.?!؟¿¡])\\s+$");
public static boolean containsOtherThan1(String str) { public static boolean containsOtherThan1(String str) {
return str != null && containsOtherThan1.matcher(str).find(); return str != null && containsOtherThan1.matcher(str).find();

View file

@ -21,7 +21,7 @@ public class ModeABC extends InputMode {
public boolean onNumber(int number, boolean hold, int repeat) { public boolean onNumber(int number, boolean hold, int repeat) {
if (hold) { if (hold) {
reset(); reset();
suggestions.add(String.valueOf(number)); suggestions.add(language.getKeyNumber(number));
autoAcceptTimeout = 0; autoAcceptTimeout = 0;
} else if (repeat > 0) { } else if (repeat > 0) {
shouldSelectNextLetter = true; shouldSelectNextLetter = true;
@ -70,11 +70,16 @@ public class ModeABC extends InputMode {
return textCase == CASE_LOWER ? "abc" : "ABC"; return textCase == CASE_LOWER ? "abc" : "ABC";
} }
String langCode = language.getLocale().getCountry(); String langCode = "";
if (language.isLatinBased() || language.isCyrillic()) {
// There are many languages written using the same alphabet, so if the user has enabled multiple,
// make it clear which one is it, by appending the country code to "ABC" or "АБВ".
langCode = language.getLocale().getCountry();
langCode = langCode.isEmpty() ? language.getLocale().getLanguage() : langCode; langCode = langCode.isEmpty() ? language.getLocale().getLanguage() : langCode;
langCode = langCode.isEmpty() ? language.getName() : langCode; langCode = langCode.isEmpty() ? language.getName() : langCode;
langCode = " / " + langCode;
String modeString = language.getAbcString() + " / " + langCode.toUpperCase(); }
String modeString = language.getAbcString() + langCode.toUpperCase();
return (textCase == CASE_LOWER) ? modeString.toLowerCase(language.getLocale()) : modeString.toUpperCase(language.getLocale()); return (textCase == CASE_LOWER) ? modeString.toLowerCase(language.getLocale()) : modeString.toUpperCase(language.getLocale());
} }

View file

@ -81,7 +81,7 @@ public class ModePredictive extends InputMode {
reset(); reset();
autoAcceptTimeout = 0; autoAcceptTimeout = 0;
disablePredictions = true; disablePredictions = true;
suggestions.add(String.valueOf(number)); suggestions.add(language.getKeyNumber(number));
} else { } else {
// words // words
super.reset(); super.reset();

View file

@ -83,6 +83,7 @@ public class AutoSpace {
|| previousChar == ']' || previousChar == ']'
|| previousChar == '%' || previousChar == '%'
|| previousChar == '»' || previousChar == '»'
|| previousChar == '؟'
|| previousChar == '“' || previousChar == '“'
|| previousChars.endsWith(" -") || previousChars.endsWith(" -")
|| previousChars.endsWith(" /") || previousChars.endsWith(" /")
@ -118,6 +119,7 @@ public class AutoSpace {
|| lastWord.equals(":") || lastWord.equals(":")
|| lastWord.equals("!") || lastWord.equals("!")
|| lastWord.equals("?") || lastWord.equals("?")
|| lastWord.equals("؟")
|| lastWord.equals(")") || lastWord.equals(")")
|| lastWord.equals("]") || lastWord.equals("]")
|| lastWord.equals("'") || lastWord.equals("'")

View file

@ -7,6 +7,14 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
public class Characters { public class Characters {
final public static ArrayList<String> ArabicNumbers = new ArrayList<>(Arrays.asList(
"٠", "١", "٢", "٣", "٤", "٥", "٦", "٧", "٨", "٩"
));
final public static ArrayList<String> PunctuationArabic = new ArrayList<>(Arrays.asList(
"،", ".", "-", "(", ")", "[", "]", "&", "~", "`", "\"", "'", "؛", ":", "!", "؟"
));
final public static ArrayList<String> PunctuationEnglish = new ArrayList<>(Arrays.asList( final public static ArrayList<String> PunctuationEnglish = new ArrayList<>(Arrays.asList(
",", ".", "-", "(", ")", "[", "]", "&", "~", "`", "'", ";", ":", "\"", "!", "?" ",", ".", "-", "(", ")", "[", "]", "&", "~", "`", "'", ";", ":", "\"", "!", "?"
)); ));

View file

@ -53,7 +53,7 @@ public class Language {
} }
Language lang = new Language(); Language lang = new Language();
lang.abcString = definition.abcString.isEmpty() ? lang.abcString : definition.abcString; lang.abcString = definition.abcString.isEmpty() ? null : definition.abcString;
lang.dictionaryFile = definition.getDictionaryFile(); lang.dictionaryFile = definition.getDictionaryFile();
lang.hasUpperCase = definition.hasUpperCase; lang.hasUpperCase = definition.hasUpperCase;
lang.locale = definitionLocale; lang.locale = definitionLocale;
@ -74,8 +74,9 @@ public class Language {
final String specialCharsPlaceholder = "SPECIAL"; final String specialCharsPlaceholder = "SPECIAL";
final String punctuationPlaceholder = "PUNCTUATION"; final String punctuationPlaceholder = "PUNCTUATION";
final String frenchStylePlaceholder = punctuationPlaceholder + "_FR"; final String arabicStylePlaceholder = punctuationPlaceholder + "_AR";
final String germanStylePlaceholder = punctuationPlaceholder + "_DE"; final String germanStylePlaceholder = punctuationPlaceholder + "_DE";
final String frenchStylePlaceholder = punctuationPlaceholder + "_FR";
ArrayList<String> keyChars = new ArrayList<>(); ArrayList<String> keyChars = new ArrayList<>();
for (String defChar : definitionChars) { for (String defChar : definitionChars) {
@ -86,12 +87,15 @@ public class Language {
case punctuationPlaceholder: case punctuationPlaceholder:
keyChars.addAll(Characters.PunctuationEnglish); keyChars.addAll(Characters.PunctuationEnglish);
break; break;
case frenchStylePlaceholder: case arabicStylePlaceholder:
keyChars.addAll(Characters.PunctuationFrench); keyChars.addAll(Characters.PunctuationArabic);
break; break;
case germanStylePlaceholder: case germanStylePlaceholder:
keyChars.addAll(Characters.PunctuationGerman); keyChars.addAll(Characters.PunctuationGerman);
break; break;
case frenchStylePlaceholder:
keyChars.addAll(Characters.PunctuationFrench);
break;
default: default:
keyChars.add(defChar); keyChars.add(defChar);
break; break;
@ -134,7 +138,6 @@ public class Language {
for (int i = 0; i < lettersList.size() && i < 3; i++) { for (int i = 0; i < lettersList.size() && i < 3; i++) {
sb.append(lettersList.get(i)); sb.append(lettersList.get(i));
} }
abcString = sb.toString(); abcString = sb.toString();
} }
@ -154,10 +157,18 @@ public class Language {
return getKeyCharacters(2, false).contains("a"); return getKeyCharacters(2, false).contains("a");
} }
public boolean isCyrillic() {
return getKeyCharacters(2, false).contains("а");
}
public boolean isGreek() { public boolean isGreek() {
return getKeyCharacters(2, false).contains("α"); return getKeyCharacters(2, false).contains("α");
} }
public boolean isArabic() {
return getKeyCharacters(3, false).contains("ا");
}
public boolean isUkrainian() { public boolean isUkrainian() {
return getKeyCharacters(3, false).contains("є"); return getKeyCharacters(3, false).contains("є");
} }
@ -243,7 +254,7 @@ public class Language {
ArrayList<String> chars = new ArrayList<>(layout.get(key)); ArrayList<String> chars = new ArrayList<>(layout.get(key));
if (includeDigit && chars.size() > 0) { if (includeDigit && chars.size() > 0) {
chars.add(String.valueOf(key)); chars.add(getKeyNumber(key));
} }
return chars; return chars;
@ -253,6 +264,14 @@ public class Language {
return getKeyCharacters(key, true); return getKeyCharacters(key, true);
} }
public String getKeyNumber(int key) {
if (key > 10 || key < 0) {
return null;
} else {
return isArabic() ? Characters.ArabicNumbers.get(key) : String.valueOf(key);
}
}
public String getDigitSequenceForWord(String word) throws InvalidLanguageCharactersException { public String getDigitSequenceForWord(String word) throws InvalidLanguageCharactersException {
StringBuilder sequence = new StringBuilder(); StringBuilder sequence = new StringBuilder();
String lowerCaseWord = word.toLowerCase(locale); String lowerCaseWord = word.toLowerCase(locale);

View file

@ -36,6 +36,7 @@ public class LanguageCollection {
return self; return self;
} }
@Nullable
public static Language getLanguage(Context context, int langId) { public static Language getLanguage(Context context, int langId) {
if (getInstance(context).languages.containsKey(langId)) { if (getInstance(context).languages.containsKey(langId)) {
return getInstance(context).languages.get(langId); return getInstance(context).languages.get(langId);

View file

@ -85,7 +85,7 @@ public class LanguageDefinition {
LanguageDefinition definition = new LanguageDefinition(); LanguageDefinition definition = new LanguageDefinition();
String value; String value;
value = getPropertyFromYaml(yaml, "absString"); value = getPropertyFromYaml(yaml, "abcString");
definition.abcString = value != null ? value : definition.abcString; definition.abcString = value != null ? value : definition.abcString;
value = getPropertyFromYaml(yaml, "dictionaryFile"); value = getPropertyFromYaml(yaml, "dictionaryFile");

View file

@ -278,6 +278,10 @@ public class SettingsStore {
public final static int PREFERENCES_CLICK_DEBOUNCE_TIME = 250; // ms public final static int PREFERENCES_CLICK_DEBOUNCE_TIME = 250; // ms
public final static byte SLOW_QUERY_TIME = 50; // ms public final static byte SLOW_QUERY_TIME = 50; // ms
public final static int SOFT_KEY_REPEAT_DELAY = 40; // ms public final static int SOFT_KEY_REPEAT_DELAY = 40; // ms
public final static float SOFT_KEY_COMPLEX_LABEL_TITLE_SIZE = 0.55f;
public final static float SOFT_KEY_COMPLEX_LABEL_ARABIC_TITLE_SIZE = 0.72f;
public final static float SOFT_KEY_COMPLEX_LABEL_SUB_TITLE_SIZE = 0.8f;
public final static int SUGGESTIONS_MAX = 20; public final static int SUGGESTIONS_MAX = 20;
public final static int SUGGESTIONS_MIN = 8; public final static int SUGGESTIONS_MIN = 8;
public final static int SUGGESTIONS_SELECT_ANIMATION_DURATION = 66; public final static int SUGGESTIONS_SELECT_ANIMATION_DURATION = 66;

View file

@ -12,18 +12,21 @@ import android.util.AttributeSet;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.View; import android.view.View;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import io.github.sspanak.tt9.Logger; import io.github.sspanak.tt9.Logger;
import io.github.sspanak.tt9.R; import io.github.sspanak.tt9.R;
import io.github.sspanak.tt9.ime.TraditionalT9; import io.github.sspanak.tt9.ime.TraditionalT9;
import io.github.sspanak.tt9.languages.Language;
import io.github.sspanak.tt9.languages.LanguageCollection;
import io.github.sspanak.tt9.preferences.SettingsStore; import io.github.sspanak.tt9.preferences.SettingsStore;
public class SoftKey extends androidx.appcompat.widget.AppCompatButton implements View.OnTouchListener, View.OnLongClickListener { public class SoftKey extends androidx.appcompat.widget.AppCompatButton implements View.OnTouchListener, View.OnLongClickListener {
protected TraditionalT9 tt9; protected TraditionalT9 tt9;
protected float COMPLEX_LABEL_TITLE_SIZE = 0.55f; protected float complexLabelTitleSize = SettingsStore.SOFT_KEY_COMPLEX_LABEL_TITLE_SIZE;
protected float COMPLEX_LABEL_SUB_TITLE_SIZE = 0.8f; protected float complexLabelSubTitleSize = SettingsStore.SOFT_KEY_COMPLEX_LABEL_SUB_TITLE_SIZE;
private boolean hold = false; private boolean hold = false;
private boolean repeat = false; private boolean repeat = false;
@ -160,6 +163,10 @@ public class SoftKey extends androidx.appcompat.widget.AppCompatButton implement
return true; return true;
} }
@Nullable protected Language getCurrentLanguage() {
return LanguageCollection.getLanguage(tt9.getApplicationContext(), tt9.getSettings().getInputLanguage());
}
/** /**
* getTitle * getTitle
* Generates the name of the key, for example: "OK", "Backspace", "1", etc... * Generates the name of the key, for example: "OK", "Backspace", "1", etc...
@ -203,9 +210,15 @@ public class SoftKey extends androidx.appcompat.widget.AppCompatButton implement
sb.append('\n'); sb.append('\n');
sb.append(subtitle); sb.append(subtitle);
sb.setSpan(new RelativeSizeSpan(COMPLEX_LABEL_TITLE_SIZE), 0, 2, Spanned.SPAN_INCLUSIVE_INCLUSIVE); float padding = SettingsStore.SOFT_KEY_COMPLEX_LABEL_TITLE_SIZE;
sb.setSpan(new StyleSpan(Typeface.ITALIC), 0, 2, Spanned.SPAN_EXCLUSIVE_INCLUSIVE); if (complexLabelTitleSize == SettingsStore.SOFT_KEY_COMPLEX_LABEL_ARABIC_TITLE_SIZE) {
sb.setSpan(new RelativeSizeSpan(COMPLEX_LABEL_SUB_TITLE_SIZE), 1, sb.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE); padding /= 10;
}
sb.setSpan(new RelativeSizeSpan(complexLabelTitleSize), 0, 1, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
sb.setSpan(new StyleSpan(Typeface.ITALIC), 0, 1, Spanned.SPAN_EXCLUSIVE_INCLUSIVE);
sb.setSpan(new RelativeSizeSpan(padding), 1, 2, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
sb.setSpan(new RelativeSizeSpan(complexLabelSubTitleSize), 2, sb.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
setText(sb); setText(sb);
} }

View file

@ -11,7 +11,7 @@ import io.github.sspanak.tt9.R;
import io.github.sspanak.tt9.ime.helpers.Key; import io.github.sspanak.tt9.ime.helpers.Key;
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.languages.LanguageCollection; import io.github.sspanak.tt9.preferences.SettingsStore;
public class SoftNumberKey extends SoftKey { public class SoftNumberKey extends SoftKey {
public SoftNumberKey(Context context) { public SoftNumberKey(Context context) {
@ -53,7 +53,16 @@ public class SoftNumberKey extends SoftKey {
@Override @Override
protected String getTitle() { protected String getTitle() {
return String.valueOf(getNumber(getId())); int number = getNumber(getId());
Language language = getCurrentLanguage();
if (language != null && language.isArabic() && tt9 != null && !tt9.isInputModeNumeric()) {
complexLabelTitleSize = SettingsStore.SOFT_KEY_COMPLEX_LABEL_ARABIC_TITLE_SIZE;
return language.getKeyNumber(number);
} else {
complexLabelTitleSize = SettingsStore.SOFT_KEY_COMPLEX_LABEL_TITLE_SIZE;
return String.valueOf(number);
}
} }
@Override @Override
@ -73,7 +82,7 @@ public class SoftNumberKey extends SoftKey {
} else if (tt9.isInputModeNumeric()) { } else if (tt9.isInputModeNumeric()) {
return "+"; return "+";
} else { } else {
COMPLEX_LABEL_SUB_TITLE_SIZE = 1; complexLabelSubTitleSize = 1;
return ""; return "";
} }
} }
@ -89,7 +98,7 @@ public class SoftNumberKey extends SoftKey {
} }
// 2-9 // 2-9
Language language = LanguageCollection.getLanguage(tt9.getApplicationContext(), tt9.getSettings().getInputLanguage()); Language language = getCurrentLanguage();
if (language == null) { if (language == null) {
Logger.d("SoftNumberKey.getLabel", "Cannot generate a label when the language is NULL."); Logger.d("SoftNumberKey.getLabel", "Cannot generate a label when the language is NULL.");
return ""; return "";

View file

@ -4,6 +4,7 @@ import android.content.Context;
import android.util.AttributeSet; import android.util.AttributeSet;
import io.github.sspanak.tt9.R; import io.github.sspanak.tt9.R;
import io.github.sspanak.tt9.languages.Language;
public class SoftPunctuationKey extends SoftKey { public class SoftPunctuationKey extends SoftKey {
public SoftPunctuationKey(Context context) { public SoftPunctuationKey(Context context) {
@ -50,7 +51,10 @@ public class SoftPunctuationKey extends SoftKey {
if (keyId == R.id.soft_key_punctuation_2) return "."; if (keyId == R.id.soft_key_punctuation_2) return ".";
} else { } else {
if (keyId == R.id.soft_key_punctuation_1) return "!"; if (keyId == R.id.soft_key_punctuation_1) return "!";
if (keyId == R.id.soft_key_punctuation_2) return "?"; if (keyId == R.id.soft_key_punctuation_2) {
Language language = getCurrentLanguage();
return language != null && language.isArabic() ? "؟" : "?";
}
} }
return ""; return "";