use dictionaries with wrong country rather than none

now e.g. pt_BR locale with also use pt_PT if only pt_BR dictionary is available
This commit is contained in:
Helium314 2023-08-19 19:12:01 +02:00
parent cee6bf65a2
commit 707a7bf48b
4 changed files with 39 additions and 22 deletions

View file

@ -33,6 +33,7 @@ import java.io.File;
import java.io.IOException;
import java.nio.BufferUnderflowException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Locale;
@ -166,16 +167,17 @@ final public class BinaryDictionaryGetter {
* @param context the context on which to open the files upon.
* @return an array of binary dictionary files, which may be empty but may not be null.
*/
public static File[] getCachedWordLists(final String locale, final Context context) {
public static File[] getCachedWordLists(final String locale, final Context context, final boolean weakMatchAcceptable) {
final File[] directoryList = DictionaryInfoUtils.getCachedDirectoryList(context);
if (null == directoryList) return EMPTY_FILE_ARRAY;
Arrays.sort(directoryList);
final HashMap<String, FileAndMatchLevel> cacheFiles = new HashMap<>();
for (File directory : directoryList) {
if (!directory.isDirectory()) continue;
final String dirLocale =
DictionaryInfoUtils.getWordListIdFromFileName(directory.getName()).toLowerCase(Locale.ENGLISH);
final int matchLevel = LocaleUtils.getMatchLevel(dirLocale, locale.toLowerCase(Locale.ENGLISH));
if (LocaleUtils.isMatch(matchLevel)) {
if (weakMatchAcceptable ? LocaleUtils.isMatchWeak(matchLevel) : LocaleUtils.isMatch(matchLevel)) {
final File[] wordLists = directory.listFiles();
if (null != wordLists) {
for (File wordList : wordLists) {
@ -243,8 +245,8 @@ final public class BinaryDictionaryGetter {
* @return The list of addresses of valid dictionary files, or null.
*/
public static ArrayList<AssetFileAddress> getDictionaryFiles(final Locale locale,
final Context context, boolean notifyDictionaryPackForUpdates) {
final File[] cachedWordLists = getCachedWordLists(locale.toString(), context);
final Context context, boolean notifyDictionaryPackForUpdates, final boolean weakMatchAcceptable) {
final File[] cachedWordLists = getCachedWordLists(locale.toString(), context, weakMatchAcceptable);
final String mainDictId = DictionaryInfoUtils.getMainDictId(locale);
final DictPackSettings dictPackSettings = new DictPackSettings(context);
@ -271,7 +273,7 @@ final public class BinaryDictionaryGetter {
}
if (!foundMainDict && dictPackSettings.isWordListActive(mainDictId)) {
final File dict = loadDictionaryFromAssets(locale.toString(), context);
final File dict = loadDictionaryFromAssets(locale.toString(), context, weakMatchAcceptable);
final AssetFileAddress fallbackAsset;
if (dict == null) {
// fall back to the old way (maybe remove? will not work if files are compressed)
@ -298,7 +300,7 @@ final public class BinaryDictionaryGetter {
*
* Returns null on IO errors or if no matching dictionary is found
*/
public static File loadDictionaryFromAssets(final String locale, final Context context) {
public static File loadDictionaryFromAssets(final String locale, final Context context, final boolean weakMatchAcceptable) {
final String[] dictionaryList = getAssetsDictionaryList(context);
if (null == dictionaryList) return null;
String bestMatchName = null;
@ -310,8 +312,9 @@ final public class BinaryDictionaryGetter {
// assets files may contain the locale in lowercase, but dictionary headers usually
// have an upper case country code, so we compare lowercase here
final int matchLevel = LocaleUtils.getMatchLevel(dictLocale.toLowerCase(Locale.ENGLISH), locale.toLowerCase(Locale.ENGLISH));
if (LocaleUtils.isMatch(matchLevel) && matchLevel > bestMatchLevel) {
if ((weakMatchAcceptable ? LocaleUtils.isMatchWeak(matchLevel) : LocaleUtils.isMatch(matchLevel)) && matchLevel > bestMatchLevel) {
bestMatchName = dictionary;
bestMatchLevel = matchLevel;
}
}
if (bestMatchName == null) return null;

View file

@ -52,20 +52,29 @@ public final class DictionaryFactory {
}
final LinkedList<Dictionary> dictList = new LinkedList<>();
final ArrayList<AssetFileAddress> assetFileList =
BinaryDictionaryGetter.getDictionaryFiles(locale, context, true);
if (null != assetFileList) {
for (final AssetFileAddress f : assetFileList) {
final ReadOnlyBinaryDictionary readOnlyBinaryDictionary =
new ReadOnlyBinaryDictionary(f.mFilename, f.mOffset, f.mLength,
false /* useFullEditDistance */, locale, Dictionary.TYPE_MAIN);
if (readOnlyBinaryDictionary.isValidDictionary()) {
dictList.add(readOnlyBinaryDictionary);
} else {
readOnlyBinaryDictionary.close();
// Prevent this dictionary to do any further harm.
killDictionary(context, f);
}
ArrayList<AssetFileAddress> assetFileList =
BinaryDictionaryGetter.getDictionaryFiles(locale, context, true, false);
boolean mainFound = false;
for (AssetFileAddress fileAddress : assetFileList) {
if (fileAddress.mFilename.contains("main")) {
mainFound = true;
break;
}
}
if (!mainFound) // try again and allow weaker match
assetFileList = BinaryDictionaryGetter.getDictionaryFiles(locale, context, true, true);
for (final AssetFileAddress f : assetFileList) {
final ReadOnlyBinaryDictionary readOnlyBinaryDictionary =
new ReadOnlyBinaryDictionary(f.mFilename, f.mOffset, f.mLength,
false /* useFullEditDistance */, locale, Dictionary.TYPE_MAIN);
if (readOnlyBinaryDictionary.isValidDictionary()) {
dictList.add(readOnlyBinaryDictionary);
} else {
readOnlyBinaryDictionary.close();
// Prevent this dictionary to do any further harm.
killDictionary(context, f);
}
}

View file

@ -161,6 +161,11 @@ public final class LocaleUtils {
return LOCALE_MATCH <= level;
}
/** similar to isMatch, but returns true if there is anything matching (used for fallback) */
public static boolean isMatchWeak(final int level) {
return level > LOCALE_NO_MATCH;
}
private static final HashMap<String, Locale> sLocaleCache = new HashMap<>();
/**

View file

@ -426,7 +426,7 @@ public class DictionaryInfoUtils {
for (final File directory : directoryList) {
final String localeString = getWordListIdFromFileName(directory.getName());
final File[] dicts = BinaryDictionaryGetter.getCachedWordLists(
localeString, context);
localeString, context, false);
for (final File dict : dicts) {
final String wordListId = getWordListIdFromFileName(dict.getName());
if (!DictionaryInfoUtils.isMainWordListId(wordListId)) {