From fd95b4dc879c146c1b1558e7ccfc0d9e8c1b5597 Mon Sep 17 00:00:00 2001 From: Helium314 Date: Mon, 19 Feb 2024 14:10:49 +0100 Subject: [PATCH] add list of known dictionaries for more convenient links --- README.md | 4 + .../main/assets/dictionaries_in_dict_repo.csv | 85 +++++++++++++++++++ .../keyboard/latin/common/LocaleUtils.kt | 2 +- .../latin/settings/LanguageSettingsDialog.kt | 35 +++++++- .../keyboard/latin/utils/DictionaryUtils.kt | 3 + app/src/main/res/values/strings.xml | 2 + settings.gradle | 1 + tools/make-dict-list/README.md | 5 ++ tools/make-dict-list/build.gradle | 18 ++++ .../main/kotlin/tools/dict/MakeDictList.kt | 63 ++++++++++++++ 10 files changed, 215 insertions(+), 3 deletions(-) create mode 100644 app/src/main/assets/dictionaries_in_dict_repo.csv create mode 100644 tools/make-dict-list/README.md create mode 100644 tools/make-dict-list/build.gradle create mode 100644 tools/make-dict-list/src/main/kotlin/tools/dict/MakeDictList.kt diff --git a/README.md b/README.md index 89222697..d655ce19 100644 --- a/README.md +++ b/README.md @@ -124,6 +124,10 @@ See [layouts.md](layouts.md#adding-new-layouts--languages) for how to add new la See make-emoji-keys tool [README](tools/make-emoji-keys/README.md). +### Update List of Existing Dictionaries + +See make-dict-list tool [README](tools/make-dict-list/README.md). + # License HeliBoard (as a fork of OpenBoard) is licensed under GNU General Public License v3.0. diff --git a/app/src/main/assets/dictionaries_in_dict_repo.csv b/app/src/main/assets/dictionaries_in_dict_repo.csv new file mode 100644 index 00000000..581fd5cf --- /dev/null +++ b/app/src/main/assets/dictionaries_in_dict_repo.csv @@ -0,0 +1,85 @@ +main,ar, +main,hy, +main,as, +main,bn, +main,by, +main,bg, +main,ca, +main,hr, +main,cs, +main,da, +main,nl, +main,en_AU, +main,en_GB, +main,en_US, +emoji,en, +main,eo, +main,fi, +emoji,fr, +main,fr, +main,gl, +main,ka, +main,de, +main,gom, +main,el, +main,gu, +main,he, +main,iw, +main,hi, +main,hi_ZZ, +main,hu, +main,it, +main,kn, +main,ks, +main,lv, +main,lt, +main,lb, +main,mai, +main,ml, +main,mr, +main,nb, +main,or, +main,pl, +main,pt_BR, +main,pt_PT, +main,pa, +main,ro, +emoji,ru, +main,ru, +main,sa, +main,sat, +main,sr_ZZ, +main,sr, +main,sd, +main,sl, +main,es, +main,sv, +main,ta, +main,te, +main,tok, +main,tcy, +main,tr, +main,uk, +main,ur, +main,af,exp +main,ar,exp +main,bn,exp +main,bg,exp +main,cs,exp +main,en_GB,exp +main,en_US,exp +symbols,en,exp +symbols,fr,exp +main,fr,exp +main,de_AT,exp +main,de,exp +main,id,exp +main,it,exp +main,kab,exp +addon,ml_ZZ,exp +main,ru,exp +main,sk,exp +main,es,exp +main,uk,exp +main,vi,exp + diff --git a/app/src/main/java/helium314/keyboard/latin/common/LocaleUtils.kt b/app/src/main/java/helium314/keyboard/latin/common/LocaleUtils.kt index 72fae76a..067b973e 100644 --- a/app/src/main/java/helium314/keyboard/latin/common/LocaleUtils.kt +++ b/app/src/main/java/helium314/keyboard/latin/common/LocaleUtils.kt @@ -91,7 +91,7 @@ object LocaleUtils { * @param tested the locale to test. * @return a constant that measures how well the tested locale matches the reference locale. */ - private fun getMatchLevel(reference: Locale, tested: Locale): Int { + fun getMatchLevel(reference: Locale, tested: Locale): Int { if (reference == tested) return LOCALE_FULL_MATCH if (reference.toString().isEmpty()) return LOCALE_ANY_MATCH if (reference.language != tested.language) return LOCALE_NO_MATCH diff --git a/app/src/main/java/helium314/keyboard/latin/settings/LanguageSettingsDialog.kt b/app/src/main/java/helium314/keyboard/latin/settings/LanguageSettingsDialog.kt index 2d980510..6f0ff0c5 100644 --- a/app/src/main/java/helium314/keyboard/latin/settings/LanguageSettingsDialog.kt +++ b/app/src/main/java/helium314/keyboard/latin/settings/LanguageSettingsDialog.kt @@ -268,10 +268,41 @@ class LanguageSettingsDialog( binding.secondaryLocales.addView(rowBinding.root) } + private fun createDictionaryText(locale: Locale, context: Context): String { + val link = "" + context.getString(R.string.dictionary_link_text) + "" + val message = context.getString(R.string.add_dictionary, link) + val knownDicts = mutableListOf() + context.assets.open("dictionaries_in_dict_repo.csv").reader().forEachLine { + if (it.isBlank()) return@forEachLine + val (type, localeString, experimental) = it.split(",") + // we use a locale string here because that's in the dictionaries repo + // ideally the repo would switch to language tag, but not sure how this is handled in the dictionary header + // further, the dicts in the dictionaries repo should be compatible with other AOSP-based keyboards + val dictLocale = localeString.constructLocale() + if (LocaleUtils.getMatchLevel(locale, dictLocale) < 3) return@forEachLine + val rawDictString = "$type: ${dictLocale.getDisplayName(context.resources.configuration.locale())}" + val dictString = if (experimental.isEmpty()) rawDictString + else context.getString(R.string.available_dictionary_experimental, rawDictString) + val dictBaseUrl = DICTIONARY_URL + DICTIONARY_DOWNLOAD_SUFFIX + + if (experimental.isEmpty()) DICTIONARY_NORMAL_SUFFIX else DICTIONARY_EXPERIMENTAL_SUFFIX + val dictLink = dictBaseUrl + type + "_" + localeString.lowercase() + ".dict" + val fullText = "
  • $dictString
  • " + knownDicts.add(fullText) + } + if (knownDicts.isEmpty()) return message + return """ +

    $message

    + ${context.getString(R.string.dictionary_available)} + + """.trimIndent() + } + private fun fillDictionariesView() { binding.addDictionary.setOnClickListener { - val link = "" + context.getString(R.string.dictionary_link_text) + "" - val message = SpannableStringUtils.fromHtml(context.getString(R.string.add_dictionary, link)) + val messageRawText = createDictionaryText(mainLocale, context) + val message = SpannableStringUtils.fromHtml(messageRawText) val dialog = Builder(context) .setTitle(R.string.add_new_dictionary_title) .setMessage(message) diff --git a/app/src/main/java/helium314/keyboard/latin/utils/DictionaryUtils.kt b/app/src/main/java/helium314/keyboard/latin/utils/DictionaryUtils.kt index 9c063e2d..4f28f43b 100644 --- a/app/src/main/java/helium314/keyboard/latin/utils/DictionaryUtils.kt +++ b/app/src/main/java/helium314/keyboard/latin/utils/DictionaryUtils.kt @@ -85,3 +85,6 @@ private fun hasAnythingOtherThanExtractedMainDictionary(dir: File) = dir.listFiles()?.any { it.name != DictionaryInfoUtils.getExtractedMainDictFilename() } != false const val DICTIONARY_URL = "https://codeberg.org/Helium314/aosp-dictionaries" +const val DICTIONARY_DOWNLOAD_SUFFIX = "/src/branch/main/" +const val DICTIONARY_NORMAL_SUFFIX = "dictionaries/" +const val DICTIONARY_EXPERIMENTAL_SUFFIX = "dictionaries_experimental/" diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 7aa22684..1f02a944 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -547,6 +547,8 @@ New dictionary: "Select a dictionary to add. Dictionaries in .dict format can be downloaded %s." "here" + + "%s (experimental)" "Error: Selected file is not a valid dictionary file" diff --git a/settings.gradle b/settings.gradle index 8335aa9f..287debfb 100755 --- a/settings.gradle +++ b/settings.gradle @@ -1,2 +1,3 @@ include ':app' include ':tools:make-emoji-keys' +include ':tools:make-dict-list' diff --git a/tools/make-dict-list/README.md b/tools/make-dict-list/README.md new file mode 100644 index 00000000..8927e592 --- /dev/null +++ b/tools/make-dict-list/README.md @@ -0,0 +1,5 @@ +# make-dict-list + +This module takes care of generating a list of dictionaries available in the [dictionaries repository](https://codeberg.org/Helium314/aosp-dictionaries) for convenient linking when adding dictionaries in HeliBoard. + +To use it, simply run `./gradlew tools:make-dict-list:makeDictList` diff --git a/tools/make-dict-list/build.gradle b/tools/make-dict-list/build.gradle new file mode 100644 index 00000000..40b2dc98 --- /dev/null +++ b/tools/make-dict-list/build.gradle @@ -0,0 +1,18 @@ +apply plugin: "java" +apply plugin: 'kotlin' + +ext { + javaMainClass = "tools.dict.MakeDictList" +} + +java { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 +} + +tasks.register('makeDictList', JavaExec) { + args project.rootProject.project('app').projectDir.path + File.separator + 'src' + + File.separator + 'main' + File.separator + 'assets' + classpath = sourceSets.main.runtimeClasspath + main = javaMainClass +} diff --git a/tools/make-dict-list/src/main/kotlin/tools/dict/MakeDictList.kt b/tools/make-dict-list/src/main/kotlin/tools/dict/MakeDictList.kt new file mode 100644 index 00000000..7ca864ee --- /dev/null +++ b/tools/make-dict-list/src/main/kotlin/tools/dict/MakeDictList.kt @@ -0,0 +1,63 @@ +package tools.dict + +import java.io.File +import java.net.URL + +class MakeDictList { + + companion object { + + @JvmStatic fun main(args: Array) { + val readmeUrl = "https://codeberg.org/Helium314/aosp-dictionaries/raw/branch/main/README.md" + val readmeText = URL(readmeUrl).readText() + val fileText = doIt(readmeText) + val targetDir = args[0] + + File(targetDir).mkdirs() + File("$targetDir/dictionaries_in_dict_repo.csv").writeText(fileText) + } + + } +} + +/** + * extract dictionary list from README.md + * output format: ,, + * is empty if dictionary is not experimental, no other check done + * requires README.md to have dicts in correct "# Dictionaries" or "# Experimental dictionaries" sections + */ +private fun doIt(readme: String): String { + // output format: ,, + // experimental is empty if dictionary is not experimental, no other check done + var mode = MODE_NOTHING + val outLines = mutableListOf() + readme.split("\n").forEach { line -> + if (line.startsWith("#")) { + mode = if (line.trim() == "# Dictionaries") + MODE_NORMAL + else if (line.trim() == "# Experimental dictionaries") + MODE_EXPERIMENTAL + else + MODE_NOTHING + return@forEach + } + if (mode == MODE_NOTHING || !line.startsWith("*")) return@forEach + val dictName = line.substringAfter("]").substringAfter("(").substringBefore(")") + .substringAfterLast("/").substringBefore(".dict") + val type = dictName.substringBefore("_") + val rawLocale = dictName.substringAfter("_") + val locale = if ("_" !in rawLocale) rawLocale + else { + val split = rawLocale.split("_").toMutableList() + if (!split[1].startsWith("#")) + split[1] = split[1].uppercase() + split.joinToString("_") + } + outLines.add("$type,$locale,${if (mode == MODE_EXPERIMENTAL) "exp" else ""}") + } + return outLines.joinToString("\n") + "\n" +} + +private const val MODE_NOTHING = 0 +private const val MODE_NORMAL = 1 +private const val MODE_EXPERIMENTAL = 2