add list of known dictionaries for more convenient links

This commit is contained in:
Helium314 2024-02-19 14:10:49 +01:00
parent b1eb33f6e2
commit fd95b4dc87
10 changed files with 215 additions and 3 deletions

View file

@ -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). 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 # License
HeliBoard (as a fork of OpenBoard) is licensed under GNU General Public License v3.0. HeliBoard (as a fork of OpenBoard) is licensed under GNU General Public License v3.0.

View file

@ -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
1 main ar
2 main hy
3 main as
4 main bn
5 main by
6 main bg
7 main ca
8 main hr
9 main cs
10 main da
11 main nl
12 main en_AU
13 main en_GB
14 main en_US
15 emoji en
16 main eo
17 main fi
18 emoji fr
19 main fr
20 main gl
21 main ka
22 main de
23 main gom
24 main el
25 main gu
26 main he
27 main iw
28 main hi
29 main hi_ZZ
30 main hu
31 main it
32 main kn
33 main ks
34 main lv
35 main lt
36 main lb
37 main mai
38 main ml
39 main mr
40 main nb
41 main or
42 main pl
43 main pt_BR
44 main pt_PT
45 main pa
46 main ro
47 emoji ru
48 main ru
49 main sa
50 main sat
51 main sr_ZZ
52 main sr
53 main sd
54 main sl
55 main es
56 main sv
57 main ta
58 main te
59 main tok
60 main tcy
61 main tr
62 main uk
63 main ur
64 main af exp
65 main ar exp
66 main bn exp
67 main bg exp
68 main cs exp
69 main en_GB exp
70 main en_US exp
71 symbols en exp
72 symbols fr exp
73 main fr exp
74 main de_AT exp
75 main de exp
76 main id exp
77 main it exp
78 main kab exp
79 addon ml_ZZ exp
80 main ru exp
81 main sk exp
82 main es exp
83 main uk exp
84 main vi exp

View file

@ -91,7 +91,7 @@ object LocaleUtils {
* @param tested the locale to test. * @param tested the locale to test.
* @return a constant that measures how well the tested locale matches the reference locale. * @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 == tested) return LOCALE_FULL_MATCH
if (reference.toString().isEmpty()) return LOCALE_ANY_MATCH if (reference.toString().isEmpty()) return LOCALE_ANY_MATCH
if (reference.language != tested.language) return LOCALE_NO_MATCH if (reference.language != tested.language) return LOCALE_NO_MATCH

View file

@ -268,10 +268,41 @@ class LanguageSettingsDialog(
binding.secondaryLocales.addView(rowBinding.root) binding.secondaryLocales.addView(rowBinding.root)
} }
private fun createDictionaryText(locale: Locale, context: Context): String {
val link = "<a href='$DICTIONARY_URL'>" + context.getString(R.string.dictionary_link_text) + "</a>"
val message = context.getString(R.string.add_dictionary, link)
val knownDicts = mutableListOf<String>()
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 = "<li><a href='$dictLink'>$dictString</a></li>"
knownDicts.add(fullText)
}
if (knownDicts.isEmpty()) return message
return """
<p>$message</p>
<b>${context.getString(R.string.dictionary_available)}</b>
<ul>
${knownDicts.joinToString("\n")}
</ul>
""".trimIndent()
}
private fun fillDictionariesView() { private fun fillDictionariesView() {
binding.addDictionary.setOnClickListener { binding.addDictionary.setOnClickListener {
val link = "<a href='$DICTIONARY_URL'>" + context.getString(R.string.dictionary_link_text) + "</a>" val messageRawText = createDictionaryText(mainLocale, context)
val message = SpannableStringUtils.fromHtml(context.getString(R.string.add_dictionary, link)) val message = SpannableStringUtils.fromHtml(messageRawText)
val dialog = Builder(context) val dialog = Builder(context)
.setTitle(R.string.add_new_dictionary_title) .setTitle(R.string.add_new_dictionary_title)
.setMessage(message) .setMessage(message)

View file

@ -85,3 +85,6 @@ private fun hasAnythingOtherThanExtractedMainDictionary(dir: File) =
dir.listFiles()?.any { it.name != DictionaryInfoUtils.getExtractedMainDictFilename() } != false dir.listFiles()?.any { it.name != DictionaryInfoUtils.getExtractedMainDictFilename() } != false
const val DICTIONARY_URL = "https://codeberg.org/Helium314/aosp-dictionaries" 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/"

View file

@ -547,6 +547,8 @@ New dictionary:
<string name="add_dictionary">"Select a dictionary to add. Dictionaries in .dict format can be downloaded %s."</string> <string name="add_dictionary">"Select a dictionary to add. Dictionaries in .dict format can be downloaded %s."</string>
<!-- Title of the link to the download page inserted into messages (add_dictionary and no_dictionary_message) --> <!-- Title of the link to the download page inserted into messages (add_dictionary and no_dictionary_message) -->
<string name="dictionary_link_text">"here"</string> <string name="dictionary_link_text">"here"</string>
<!-- Title of an item in the list of available dictionaries when the dictionary is experimental. This string will be interpreted as HTML -->
<string name="available_dictionary_experimental">"%s (experimental)"</string>
<!-- Text shown when dictionary file could not be read --> <!-- Text shown when dictionary file could not be read -->
<string name="dictionary_file_error">"Error: Selected file is not a valid dictionary file"</string> <string name="dictionary_file_error">"Error: Selected file is not a valid dictionary file"</string>
<!-- Text shown when dictionary file is not for the selected locale --> <!-- Text shown when dictionary file is not for the selected locale -->

View file

@ -1,2 +1,3 @@
include ':app' include ':app'
include ':tools:make-emoji-keys' include ':tools:make-emoji-keys'
include ':tools:make-dict-list'

View file

@ -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`

View file

@ -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
}

View file

@ -0,0 +1,63 @@
package tools.dict
import java.io.File
import java.net.URL
class MakeDictList {
companion object {
@JvmStatic fun main(args: Array<String>) {
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: <localeString>,<type>,<experimental>
* <experimental> 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: <localeString>,<type>,<experimental>
// experimental is empty if dictionary is not experimental, no other check done
var mode = MODE_NOTHING
val outLines = mutableListOf<String>()
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