abouttreesummaryrefslogcommitdiff
path: root/gen_method_xml.py
diff options
context:
space:
mode:
authorJules Aguillon2026-02-02 00:20:00 +0100
committerGitHub2026-02-02 00:20:00 +0100
commit77c4a27c4c37b3620defcab94ffd1b2f536c88cb (patch)
tree1bf2c5b723e1f86b0904257e7e57f4fda15378e9 /gen_method_xml.py
parent2ecf93d9904544ee73159e9f0ee74b49057bca6c (diff)
downloadunexpected-keyboard-77c4a27c4c37b3620defcab94ffd1b2f536c88cb.tar.gz
unexpected-keyboard-77c4a27c4c37b3620defcab94ffd1b2f536c88cb.zip
Spell checking (#1137)
This adds dictionary-based spell checking to the keyboard. The keyboard looks at the word being typed and matches it against a dictionary to either complete the rest of the word or find alternative spellings. The core of this feature is implemented in cdict, which is included as a submodule in vendor/cidct. Cdict is developped at https://github.com/Julow/cdict The dictionaries are hosted at https://github.com/Julow/Unexpected-Keyboard-dictionaries/ The wordlists used to build the dictionaries are the same ones used by HeliBoard from https://codeberg.org/Helium314/aosp-dictionaries - Add an activity accessible from the launcher app that lists available dictionaries with a download button. The DictionaryListView view shows the list of available dictionaries and handles downloading and installing them. - The Dictionaries class manages installed dictionaries. Dictionaries are installed as individual files into the app's private directory. - Available dictionaries are listed in dictionaries.xml, which is generated when building Unexpected-Keyboard-dictionaries. method.xml mentions the dictionary name for each locales.
Diffstat (limited to 'gen_method_xml.py')
-rw-r--r--gen_method_xml.py63
1 files changed, 48 insertions, 15 deletions
diff --git a/gen_method_xml.py b/gen_method_xml.py
index 3b1962f..c01f212 100644
--- a/gen_method_xml.py
+++ b/gen_method_xml.py
@@ -1,3 +1,4 @@
+import xml.etree.ElementTree as ET
import itertools as it
# This script generates res/xml/method.xml.
@@ -78,37 +79,69 @@ LOCALES = [
]
# The locale that is at the beginning of the list
-DEFAULT_LOCALE = loc("en", "latin", "latn_qwerty_us", tag="en")
+DEFAULT_LOCALE = loc("en", "latin", "latn_qwerty_us", tag="en", dictionary="en_US")
-def loc_to_subtype(loc):
+def parse_dictionaries():
+ tree = ET.parse("res/values/dictionaries.xml")
+ root = tree.getroot()
+ return set(( it.text for it in root.findall('*[@name="dictionaries_locale"]/item') ))
+
+# Available dictionares of the form "de" or "de_CH".
+available_dictionaries = parse_dictionaries()
+
+def subtype_elem(root, loc):
tag = loc["tag"].replace("_", "-")
extra_keys = ",extra_keys=" + loc["extra_keys"] if "extra_keys" in loc else ""
- return f'<subtype android:label="%s" android:languageTag="{tag}" android:imeSubtypeLocale="{loc["name"]}" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script={loc["script"]},default_layout={loc["default_layout"]}{extra_keys}"/>'
+ dictionaries = ",dictionary=" + loc["dictionary"] if loc["dictionary"] != None else ""
+ extra_value = f'script={loc["script"]},default_layout={loc["default_layout"]}{dictionaries}{extra_keys}'
+ ET.SubElement(root, "subtype", attrib={
+ "android:label": "%s",
+ "android:languageTag": tag,
+ "android:imeSubtypeLocale": loc["name"],
+ "android:imeSubtypeMode": "keyboard",
+ "android:isAsciiCapable": "true",
+ "android:imeSubtypeExtraValue": extra_value
+ })
-# Return locales in sorted order with the 'tag' item added.
-def compute_tags():
+# Return locales in sorted order with the "tag" and "dictionary" attributes
+# added.
+def compute_attrs():
+ locales_grouped = {} # Locales grouped by language tag
def lang(loc):
return loc["name"].split("_")[0]
- locales_grouped = { k: list(v) for k, v in it.groupby(sorted(LOCALES, key=lang), lang) }
+ for loc in LOCALES:
+ locales_grouped.setdefault(lang(loc), []).append(loc)
def tag(loc):
if "tag" in loc: return loc["tag"]
l = lang(loc)
if loc["name"] == f"{l}_{l.upper()}": return l # Locales like "fr_FR"
# Return a short tag when it's not shared between several locales
return l if len(locales_grouped[l]) == 1 else loc["name"]
- return [ dict(tag=tag(loc), **loc) for loc in LOCALES ]
+ def dictionary(loc):
+ if loc["name"] in available_dictionaries: return loc["name"]
+ l = lang(loc)
+ if l in available_dictionaries: return l
+ return None
+ def add_attrs(loc):
+ return dict(tag=tag(loc), dictionary=dictionary(loc), **loc)
+ return map(add_attrs, LOCALES)
def gen():
- locales = compute_tags()
- print(f"""<?xml version="1.0" encoding="utf-8"?>
-<input-method xmlns:android="http://schemas.android.com/apk/res/android" android:settingsActivity="juloo.keyboard2.SettingsActivity" android:supportsSwitchingToNextInputMethod="true">
- <!-- This file is automatically generated. DO NOT EDIT.
+ locales = compute_attrs()
+ root = ET.Element("input-method", attrib={
+ "xmlns:android": "http://schemas.android.com/apk/res/android",
+ "android:settingsActivity": "juloo.keyboard2.SettingsActivity",
+ "android:supportsSwitchingToNextInputMethod": "true",
+ })
+ root.append(ET.Comment(text=""" This file is automatically generated. DO NOT EDIT.
Locales definitions should go into 'gen_method_xml.py'.
Update this file with 'gradle test'.
- -->
- {loc_to_subtype(DEFAULT_LOCALE)}
- {"\n ".join(sorted(map(loc_to_subtype, locales)))}
-</input-method>""")
+ """))
+ subtype_elem(root, DEFAULT_LOCALE)
+ for loc in sorted(locales, key=lambda loc: loc["name"]):
+ subtype_elem(root, loc)
+ ET.indent(root)
+ print(ET.tostring(root, encoding="utf-8", xml_declaration=True).decode("UTF-8"))
gen()