Skip to content

Commit

Permalink
Auto-detect locale on Android (#13561)
Browse files Browse the repository at this point in the history
  • Loading branch information
grorp committed Jun 5, 2023
1 parent a857c46 commit a146326
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 49 deletions.
27 changes: 25 additions & 2 deletions android/app/src/main/java/net/minetest/minetest/GameActivity.java
Expand Up @@ -39,6 +39,7 @@
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).
Expand All @@ -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);
Expand Down Expand Up @@ -203,4 +202,28 @@ public void shareFile(String path) {
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;
}
}
5 changes: 4 additions & 1 deletion src/gettext.cpp
Expand Up @@ -203,7 +203,10 @@ void init_gettext(const char *path, const std::string &configured_language,
#endif // ifndef _WIN32
}
else {
/* set current system default locale */
#ifdef __ANDROID__
setenv("LANG", porting::getLanguageAndroid().c_str(), 1);
#endif
/* set current system default locale */
setlocale(LC_ALL, "");
}

Expand Down
82 changes: 37 additions & 45 deletions src/porting_android.cpp
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand All @@ -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;
}

Expand All @@ -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
Expand All @@ -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();
}
Expand All @@ -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());
Expand All @@ -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);
Expand All @@ -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);
Expand All @@ -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);
}
Expand All @@ -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
Expand All @@ -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;
}

Expand All @@ -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);
Expand All @@ -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
}
3 changes: 2 additions & 1 deletion src/porting_android.h
Expand Up @@ -43,7 +43,6 @@ void cleanupAndroid();

/**
* Initializes path_* variables for Android
* @param env Android JNI environment
*/
void initializePathsAndroid();

Expand Down Expand Up @@ -83,4 +82,6 @@ std::string getInputDialogValue();
float getDisplayDensity();
v2u32 getDisplaySize();
#endif

std::string getLanguageAndroid();
}

0 comments on commit a146326

Please sign in to comment.