Auto-detect locale on Android (#13561)

This commit is contained in:
Gregor Parzefall 2023-06-05 12:02:10 +02:00 committed by GitHub
parent a857c46e6e
commit a1463263b5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 68 additions and 49 deletions

@ -39,6 +39,7 @@ import androidx.appcompat.app.AlertDialog;
import androidx.core.content.FileProvider;
import java.io.File;
import java.util.Locale;
import java.util.Objects;
// Native code finds these methods by name (see porting_android.cpp).
@ -54,8 +55,6 @@ public class GameActivity extends NativeActivity {
private int messageReturnCode = -1;
private String messageReturnValue = "";
public static native void putMessageBoxResult(String text);
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@ -203,4 +202,28 @@ public class GameActivity extends NativeActivity {
Intent shareIntent = Intent.createChooser(intent, null);
startActivity(shareIntent);
}
public String getLanguage() {
String langCode = Locale.getDefault().getLanguage();
// getLanguage() still uses old language codes to preserve compatibility.
// List of code changes in ISO 639-2:
// https://www.loc.gov/standards/iso639-2/php/code_changes.php
switch (langCode) {
case "in":
langCode = "id"; // Indonesian
break;
case "iw":
langCode = "he"; // Hebrew
break;
case "ji":
langCode = "yi"; // Yiddish
break;
case "jw":
langCode = "jv"; // Javanese
break;
}
return langCode;
}
}

@ -203,6 +203,9 @@ void init_gettext(const char *path, const std::string &configured_language,
#endif // ifndef _WIN32
}
else {
#ifdef __ANDROID__
setenv("LANG", porting::getLanguageAndroid().c_str(), 1);
#endif
/* set current system default locale */
setlocale(LC_ALL, "");
}

@ -64,21 +64,6 @@ void android_main(android_app *app)
exit(retval);
}
/**
* Handler for finished message box input
* Intentionally NOT in namespace porting
* ToDo: this doesn't work as expected, there's a workaround for it right now
*/
extern "C" {
JNIEXPORT void JNICALL Java_net_minetest_minetest_GameActivity_putMessageBoxResult(
JNIEnv *env, jclass thiz, jstring text)
{
errorstream <<
"Java_net_minetest_minetest_GameActivity_putMessageBoxResult got: " <<
std::string((const char*) env->GetStringChars(text, nullptr)) << std::endl;
}
}
namespace porting {
android_app *app_global;
JNIEnv *jnienv;
@ -118,7 +103,7 @@ void initAndroid()
nativeActivity = findClass("net/minetest/minetest/GameActivity");
if (nativeActivity == nullptr)
errorstream <<
"porting::initAndroid unable to find java native activity class" <<
"porting::initAndroid unable to find Java native activity class" <<
std::endl;
#ifdef GPROF
@ -141,15 +126,14 @@ void cleanupAndroid()
jvm->DetachCurrentThread();
}
static std::string javaStringToUTF8(jstring js)
static std::string readJavaString(jstring j_str)
{
std::string str;
// Get string as a UTF-8 c-string
const char *c_str = jnienv->GetStringUTFChars(js, nullptr);
// Get string as a UTF-8 C string
const char *c_str = jnienv->GetStringUTFChars(j_str, nullptr);
// Save it
str = c_str;
// And free the c-string
jnienv->ReleaseStringUTFChars(js, c_str);
std::string str(c_str);
// And free the C string
jnienv->ReleaseStringUTFChars(j_str, c_str);
return str;
}
@ -162,11 +146,10 @@ void initializePathsAndroid()
FATAL_ERROR_IF(getUserDataPath==nullptr,
"porting::initializePathsAndroid unable to find Java getUserDataPath method");
jobject result = jnienv->CallObjectMethod(app_global->activity->clazz, getUserDataPath);
const char *javachars = jnienv->GetStringUTFChars((jstring) result, nullptr);
path_user = javachars;
path_share = javachars;
path_locale = path_share + DIR_DELIM + "locale";
jnienv->ReleaseStringUTFChars((jstring) result, javachars);
std::string str = readJavaString((jstring) result);
path_user = str;
path_share = str;
path_locale = str + DIR_DELIM + "locale";
}
// Set cache path
@ -176,9 +159,7 @@ void initializePathsAndroid()
FATAL_ERROR_IF(getCachePath==nullptr,
"porting::initializePathsAndroid unable to find Java getCachePath method");
jobject result = jnienv->CallObjectMethod(app_global->activity->clazz, getCachePath);
const char *javachars = jnienv->GetStringUTFChars((jstring) result, nullptr);
path_cache = javachars;
jnienv->ReleaseStringUTFChars((jstring) result, javachars);
path_cache = readJavaString((jstring) result);
migrateCachePath();
}
@ -191,7 +172,7 @@ void showInputDialog(const std::string &acceptButton, const std::string &hint,
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)V");
FATAL_ERROR_IF(showdialog == nullptr,
"porting::showInputDialog unable to find java show dialog method");
"porting::showInputDialog unable to find Java showDialog method");
jstring jacceptButton = jnienv->NewStringUTF(acceptButton.c_str());
jstring jhint = jnienv->NewStringUTF(hint.c_str());
@ -208,7 +189,7 @@ void openURIAndroid(const std::string &url)
"(Ljava/lang/String;)V");
FATAL_ERROR_IF(url_open == nullptr,
"porting::openURIAndroid unable to find java openURI method");
"porting::openURIAndroid unable to find Java openURI method");
jstring jurl = jnienv->NewStringUTF(url.c_str());
jnienv->CallVoidMethod(app_global->activity->clazz, url_open, jurl);
@ -220,7 +201,7 @@ void shareFileAndroid(const std::string &path)
"(Ljava/lang/String;)V");
FATAL_ERROR_IF(url_open == nullptr,
"porting::shareFileAndroid unable to find java openURI method");
"porting::shareFileAndroid unable to find Java shareFile method");
jstring jurl = jnienv->NewStringUTF(path.c_str());
jnienv->CallVoidMethod(app_global->activity->clazz, url_open, jurl);
@ -232,7 +213,7 @@ int getInputDialogState()
"getDialogState", "()I");
FATAL_ERROR_IF(dialogstate == nullptr,
"porting::getInputDialogState unable to find java dialog state method");
"porting::getInputDialogState unable to find Java getDialogState method");
return jnienv->CallIntMethod(app_global->activity->clazz, dialogstate);
}
@ -243,16 +224,11 @@ std::string getInputDialogValue()
"getDialogValue", "()Ljava/lang/String;");
FATAL_ERROR_IF(dialogvalue == nullptr,
"porting::getInputDialogValue unable to find java dialog value method");
"porting::getInputDialogValue unable to find Java getDialogValue method");
jobject result = jnienv->CallObjectMethod(app_global->activity->clazz,
dialogvalue);
const char *javachars = jnienv->GetStringUTFChars((jstring) result, nullptr);
std::string text(javachars);
jnienv->ReleaseStringUTFChars((jstring) result, javachars);
return text;
return readJavaString((jstring) result);
}
#ifndef SERVER
@ -266,11 +242,12 @@ float getDisplayDensity()
"getDensity", "()F");
FATAL_ERROR_IF(getDensity == nullptr,
"porting::getDisplayDensity unable to find java getDensity method");
"porting::getDisplayDensity unable to find Java getDensity method");
value = jnienv->CallFloatMethod(app_global->activity->clazz, getDensity);
firstrun = false;
}
return value;
}
@ -284,7 +261,7 @@ v2u32 getDisplaySize()
"getDisplayWidth", "()I");
FATAL_ERROR_IF(getDisplayWidth == nullptr,
"porting::getDisplayWidth unable to find java getDisplayWidth method");
"porting::getDisplayWidth unable to find Java getDisplayWidth method");
retval.X = jnienv->CallIntMethod(app_global->activity->clazz,
getDisplayWidth);
@ -293,14 +270,29 @@ v2u32 getDisplaySize()
"getDisplayHeight", "()I");
FATAL_ERROR_IF(getDisplayHeight == nullptr,
"porting::getDisplayHeight unable to find java getDisplayHeight method");
"porting::getDisplayHeight unable to find Java getDisplayHeight method");
retval.Y = jnienv->CallIntMethod(app_global->activity->clazz,
getDisplayHeight);
firstrun = false;
}
return retval;
}
std::string getLanguageAndroid()
{
jmethodID getLanguage = jnienv->GetMethodID(nativeActivity,
"getLanguage", "()Ljava/lang/String;");
FATAL_ERROR_IF(getLanguage == nullptr,
"porting::getLanguageAndroid unable to find Java getLanguage method");
jobject result = jnienv->CallObjectMethod(app_global->activity->clazz,
getLanguage);
return readJavaString((jstring) result);
}
#endif // ndef SERVER
}

@ -43,7 +43,6 @@ void cleanupAndroid();
/**
* Initializes path_* variables for Android
* @param env Android JNI environment
*/
void initializePathsAndroid();
@ -83,4 +82,6 @@ std::string getInputDialogValue();
float getDisplayDensity();
v2u32 getDisplaySize();
#endif
std::string getLanguageAndroid();
}