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 androidx.core.content.FileProvider;
import java.io.File; import java.io.File;
import java.util.Locale;
import java.util.Objects; import java.util.Objects;
// Native code finds these methods by name (see porting_android.cpp). // 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 int messageReturnCode = -1;
private String messageReturnValue = ""; private String messageReturnValue = "";
public static native void putMessageBoxResult(String text);
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
@ -203,4 +202,28 @@ public class GameActivity extends NativeActivity {
Intent shareIntent = Intent.createChooser(intent, null); Intent shareIntent = Intent.createChooser(intent, null);
startActivity(shareIntent); 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,7 +203,10 @@ void init_gettext(const char *path, const std::string &configured_language,
#endif // ifndef _WIN32 #endif // ifndef _WIN32
} }
else { else {
/* set current system default locale */ #ifdef __ANDROID__
setenv("LANG", porting::getLanguageAndroid().c_str(), 1);
#endif
/* set current system default locale */
setlocale(LC_ALL, ""); setlocale(LC_ALL, "");
} }

@ -64,21 +64,6 @@ void android_main(android_app *app)
exit(retval); 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 { namespace porting {
android_app *app_global; android_app *app_global;
JNIEnv *jnienv; JNIEnv *jnienv;
@ -118,7 +103,7 @@ void initAndroid()
nativeActivity = findClass("net/minetest/minetest/GameActivity"); nativeActivity = findClass("net/minetest/minetest/GameActivity");
if (nativeActivity == nullptr) if (nativeActivity == nullptr)
errorstream << errorstream <<
"porting::initAndroid unable to find java native activity class" << "porting::initAndroid unable to find Java native activity class" <<
std::endl; std::endl;
#ifdef GPROF #ifdef GPROF
@ -141,15 +126,14 @@ void cleanupAndroid()
jvm->DetachCurrentThread(); 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
// Get string as a UTF-8 c-string const char *c_str = jnienv->GetStringUTFChars(j_str, nullptr);
const char *c_str = jnienv->GetStringUTFChars(js, nullptr);
// Save it // Save it
str = c_str; std::string str(c_str);
// And free the c-string // And free the C string
jnienv->ReleaseStringUTFChars(js, c_str); jnienv->ReleaseStringUTFChars(j_str, c_str);
return str; return str;
} }
@ -162,11 +146,10 @@ void initializePathsAndroid()
FATAL_ERROR_IF(getUserDataPath==nullptr, FATAL_ERROR_IF(getUserDataPath==nullptr,
"porting::initializePathsAndroid unable to find Java getUserDataPath method"); "porting::initializePathsAndroid unable to find Java getUserDataPath method");
jobject result = jnienv->CallObjectMethod(app_global->activity->clazz, getUserDataPath); jobject result = jnienv->CallObjectMethod(app_global->activity->clazz, getUserDataPath);
const char *javachars = jnienv->GetStringUTFChars((jstring) result, nullptr); std::string str = readJavaString((jstring) result);
path_user = javachars; path_user = str;
path_share = javachars; path_share = str;
path_locale = path_share + DIR_DELIM + "locale"; path_locale = str + DIR_DELIM + "locale";
jnienv->ReleaseStringUTFChars((jstring) result, javachars);
} }
// Set cache path // Set cache path
@ -176,9 +159,7 @@ void initializePathsAndroid()
FATAL_ERROR_IF(getCachePath==nullptr, FATAL_ERROR_IF(getCachePath==nullptr,
"porting::initializePathsAndroid unable to find Java getCachePath method"); "porting::initializePathsAndroid unable to find Java getCachePath method");
jobject result = jnienv->CallObjectMethod(app_global->activity->clazz, getCachePath); jobject result = jnienv->CallObjectMethod(app_global->activity->clazz, getCachePath);
const char *javachars = jnienv->GetStringUTFChars((jstring) result, nullptr); path_cache = readJavaString((jstring) result);
path_cache = javachars;
jnienv->ReleaseStringUTFChars((jstring) result, javachars);
migrateCachePath(); 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"); "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)V");
FATAL_ERROR_IF(showdialog == nullptr, 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 jacceptButton = jnienv->NewStringUTF(acceptButton.c_str());
jstring jhint = jnienv->NewStringUTF(hint.c_str()); jstring jhint = jnienv->NewStringUTF(hint.c_str());
@ -208,7 +189,7 @@ void openURIAndroid(const std::string &url)
"(Ljava/lang/String;)V"); "(Ljava/lang/String;)V");
FATAL_ERROR_IF(url_open == nullptr, 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()); jstring jurl = jnienv->NewStringUTF(url.c_str());
jnienv->CallVoidMethod(app_global->activity->clazz, url_open, jurl); jnienv->CallVoidMethod(app_global->activity->clazz, url_open, jurl);
@ -220,7 +201,7 @@ void shareFileAndroid(const std::string &path)
"(Ljava/lang/String;)V"); "(Ljava/lang/String;)V");
FATAL_ERROR_IF(url_open == nullptr, 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()); jstring jurl = jnienv->NewStringUTF(path.c_str());
jnienv->CallVoidMethod(app_global->activity->clazz, url_open, jurl); jnienv->CallVoidMethod(app_global->activity->clazz, url_open, jurl);
@ -232,7 +213,7 @@ int getInputDialogState()
"getDialogState", "()I"); "getDialogState", "()I");
FATAL_ERROR_IF(dialogstate == nullptr, 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); return jnienv->CallIntMethod(app_global->activity->clazz, dialogstate);
} }
@ -243,16 +224,11 @@ std::string getInputDialogValue()
"getDialogValue", "()Ljava/lang/String;"); "getDialogValue", "()Ljava/lang/String;");
FATAL_ERROR_IF(dialogvalue == nullptr, 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, jobject result = jnienv->CallObjectMethod(app_global->activity->clazz,
dialogvalue); dialogvalue);
return readJavaString((jstring) result);
const char *javachars = jnienv->GetStringUTFChars((jstring) result, nullptr);
std::string text(javachars);
jnienv->ReleaseStringUTFChars((jstring) result, javachars);
return text;
} }
#ifndef SERVER #ifndef SERVER
@ -266,11 +242,12 @@ float getDisplayDensity()
"getDensity", "()F"); "getDensity", "()F");
FATAL_ERROR_IF(getDensity == nullptr, 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); value = jnienv->CallFloatMethod(app_global->activity->clazz, getDensity);
firstrun = false; firstrun = false;
} }
return value; return value;
} }
@ -284,7 +261,7 @@ v2u32 getDisplaySize()
"getDisplayWidth", "()I"); "getDisplayWidth", "()I");
FATAL_ERROR_IF(getDisplayWidth == nullptr, 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, retval.X = jnienv->CallIntMethod(app_global->activity->clazz,
getDisplayWidth); getDisplayWidth);
@ -293,14 +270,29 @@ v2u32 getDisplaySize()
"getDisplayHeight", "()I"); "getDisplayHeight", "()I");
FATAL_ERROR_IF(getDisplayHeight == nullptr, 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, retval.Y = jnienv->CallIntMethod(app_global->activity->clazz,
getDisplayHeight); getDisplayHeight);
firstrun = false; firstrun = false;
} }
return retval; 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 #endif // ndef SERVER
} }

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