如何让 Android 布局文件知道选择了不同的语言

问题描述

我有一个带有用于语言选择的片段 (FR_LanguageSelection) 的应用程序,您可以在这里看到:

package com.example.td.bapp;

import android.os.Bundle;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.navigation.Navigation;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.example.td.bapp.databinding.FragmentLanguageSelectionBinding;

/**

  Fragment for selecting the language of the app via ImageButtons
 *
 */

public class FR_LanguageSelection extends Fragment implements View.OnClickListener {



    /*
    String specifying the language of the App
     */
    public static String currentLanguageOfTheApp;
    public static final String LANGUAGE_GERMAN = "German";
    public static final String LANGUAGE_ENGLISH = "English";


    public FR_LanguageSelection() {
        // required empty public constructor
    }


    public static FR_LanguageSelection newInstance(String param1,String param2) {
        FR_LanguageSelection fragment = new FR_LanguageSelection();

        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

    }


    private FragmentLanguageSelectionBinding binding;

    @Override
    public View onCreateView(LayoutInflater inflater,ViewGroup container,Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        binding = FragmentLanguageSelectionBinding.inflate(inflater,container,false);
        return binding.getRoot();
    }

    @Override
    public void onViewCreated(@NonNull View view,@Nullable Bundle savedInstanceState) {
        super.onViewCreated(view,savedInstanceState);
        binding.imageButtonGermany.setonClickListener(this);
        binding.imageButtonUK.setonClickListener(this);
    }


    public void onDestroyView() {
        super.onDestroyView();
        binding = null;
    }

    @Override
    public void onClick(View view) {

        if(view.getId() == R.id.imageButtonGermany) {
            this.currentLanguageOfTheApp = LANGUAGE_GERMAN;
            Navigation.findNavController(view).navigate
                    (FR_LanguageSelectionDirections.actionFRLanguageSelectionToFRMenu());


        }

        if(view.getId() == R.id.imageButtonUK) {
            this.currentLanguageOfTheApp = LANGUAGE_ENGLISH;
            Navigation.findNavController(view).navigate(FR_LanguageSelectionDirections.actionFRLanguageSelectionToFRMenu());
        }

        }




}

因此用户只需选择一种语言,然后在其他片段中需要的静态变量中选择该语言,例如用于数据库查询。基本上这可以正常工作。但是,我创建了 XML 布局文件,这些文件使用两种不同语言的字符串资源。这是一个带有字符串 ressource "android:text="@string/size""

的 textView 示例
<TextView
    android:id="@+id/textViewS"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/size"
    android:textColor="#000000"
    android:textSize="@dimen/_15ssp"
    android:textStyle="bold"
    app:layout_constraintBottom_toBottomOf="@+id/radioGroup_Size"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintHorizontal_bias="0.025"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="@+id/radioGroup_Size"
    app:layout_constraintVertical_bias="0.50" />

现在我的问题是,我如何告诉这个布局文件它应该根据用户选择的语言使用字符串资源?我可以直接从 FR_LanguageSelection 执行此操作,还是必须以编程方式在每个 Fragment 的 Java 类中执行此操作(我认为这没有意义,因为如果是这样,我为什么要定义字符串资源)?

感谢您的每一条评论,并非常感谢您的帮助。

更新:

我刚刚将“SlothCoding”的建议代码(参见他的回答)复制到我的语言选择片段中。因此,当用户通过 onClick 方法中的 ImageButton 选择德语语言时,应执行代码(因此应设置应用程序的当前语言)。不幸的是,编译器告诉我一个错误:“无法解析符号‘活动’”。可能是因为我使用了单活动多片段方法而导致错误

这是更新的类:

package com.example.td.bapp;

import android.content.Contextwrapper;
import android.content.res.Configuration;
import android.os.Build;
import android.os.Bundle;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.fragment.app.Fragment;
import androidx.navigation.Navigation;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.example.td.bapp.databinding.FragmentLanguageSelectionBinding;

import java.util.Locale;

/**

  Fragment for selecting the language of the app via ImageButtons
 *
 */

public class FR_LanguageSelection extends Fragment implements View.OnClickListener {



    /*
    String specifying the language of the App
     */
    public static String currentLanguageOfTheApp;
    public static final String LANGUAGE_GERMAN = "German";
    public static final String LANGUAGE_ENGLISH = "English";


    public FR_LanguageSelection() {
        // required empty public constructor
    }


    public static FR_LanguageSelection newInstance(String param1,savedInstanceState);
        binding.imageButtonGermany.setonClickListener(this);
        binding.imageButtonUK.setonClickListener(this);
    }


    public void onDestroyView() {
        super.onDestroyView();
        binding = null;
    }

    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)
    @Override
    public void onClick(View view) {

        if(view.getId() == R.id.imageButtonGermany) {
            this.currentLanguageOfTheApp = LANGUAGE_GERMAN;

            Locale locale;
            locale = new Locale("de","DE");

            Configuration config = new Configuration(activity.getBaseContext().getResources().getConfiguration());
            Locale.setDefault(locale);
            config.setLocale(locale);

            activity.getBaseContext().getResources().updateConfiguration(config,activity.getBaseContext().getResources().getdisplayMetrics());

            Navigation.findNavController(view).navigate
                    (FR_LanguageSelectionDirections.actionFRLanguageSelectionToFRMenu());


        }

        if(view.getId() == R.id.imageButtonUK) {
            this.currentLanguageOfTheApp = LANGUAGE_ENGLISH;
            Navigation.findNavController(view).navigate(FR_LanguageSelectionDirections.actionFRLanguageSelectionToFRMenu());
        }

        }




}

解决方法

这不是执行此操作的最佳方法,因为 Android 应使用手机的区域设置来设置应用程序的默认语言。但是一年前我不得不在我的应用程序中做同样的事情,我被迫在应用程序中使用语言环境配置。这是怎么回事。首先,我要求用户选择他想要的语言并将其保存在我的 SharedPreferences 中。我有一个我创建为 JSONObjects 的语言列表,其中有

  • language_name(例如英语)
  • language_code(例如英语)
  • language_script(例如美国)

我是这样做的:

language_object = new JSONObject();
language_object.put("language_name","Deutsch");
language_object.put("language_code","de");
language_object.put("language_script","LT");
languages.put(language_object);

language_object = new JSONObject();
language_object.put("language_name","English");
language_object.put("language_code","en");
language_object.put("language_script","US");
languages.put(language_object);

现在我使用 ListView 显示这些语言的列表并处理 LanguageListAdapter 内的点击。当用户选择他想要的语言时,我会在 ListAdapter 中执行此操作:

@Override
public View getView(final int position,View convertView,ViewGroup parent) {

    if(convertView == null) {
        LayoutInflater layout_inflater = LayoutInflater.from(_context);
        convertView = layout_inflater.inflate(R.layout.item_language,parent,false);
    }

    try {

        JSONObject object = _data_set.getJSONObject(position);

        TextView lang_name = convertView.findViewById(R.id.language_name);
        lang_name.setText(object.getString("language_name"));

        convertView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {

                    SharedPreferences shared_preferences = activity.getBaseContext().getSharedPreferences("MY_PREFERENCES",MODE_PRIVATE);
                    SharedPreferences.Editor preferences_editor = shared_preferences.edit();
                    preferences_editor.putString("MY_LANGUAGE",object.toString());
                    preferences_editor.apply();

                    common.setLocale(activity);

                    Intent intent = new Intent(activity,LoadingActivity.class);
                    activity.startActivity(intent);
                    activity.finish();
                } catch (Exception e) {
                    e.getMessage();
                }

            }
        });
    } catch (Exception e) {
        e.getMessage();
    }
    return convertView;
}

我的函数 setLocale(Activity activity) 位于名为 common 的单独类中。我使用这个类来存储我在整个应用程序中经常使用的函数。这是它的样子:

public static void setLocale(Activity activity){

    try {
        SharedPreferences shared_preferences = activity.getBaseContext().getSharedPreferences("MY_PREFERENCES",MODE_PRIVATE);
        String language = shared_preferences.getString("MY_LANGUAGE","");

        JSONObject object = new JSONObject(language);

        Locale locale;
        locale = new Locale(object.getString("language_code"),object.getString("language_script"));
        Configuration config = new Configuration(activity.getBaseContext().getResources().getConfiguration());
        Locale.setDefault(locale);
        config.setLocale(locale);

        activity.getBaseContext().getResources().updateConfiguration(config,activity.getBaseContext().getResources().getDisplayMetrics());
    } catch (Exception e) {
        e.getMessage();
    }
}

这会设置我想要的语言并使用基于 strings.xmllanguage_codelanguage_script。因此,在我的 res > values 中,例如:

  • strings.xml - 默认语言
  • strings.xml(en-rUS) - 英语语言
  • strings.xml(de-rLT) - 自定义德语(自定义是指自定义代码脚本标签)

现在,每当用户选择德语时,我都会将“de-LT”保存为语言代码并在 setLocale 中使用它,以便应用可以从 strings.xml资源。


编辑:如何为每种语言创建 strings.xml

因此,要执行此操作,您需要先转到 res > values 文件夹。在那里您将拥有默认的 strings.xml 文件。当您没有为用户的区域电话设置定义 strings.xml 时使用此方法。默认情况下,如果应用程序可以在国际上使用,这应该是英文,原因很简单,你可能知道为什么。

在此 strings.xml 中,您可以定义您在应用程序中使用的所有字符串,并按如下方式进行操作:

<resources>
    <string name="app_name">TempProject</string>

    <string name="Size">Size</string>

</resources>

现在,您要为德语和克罗地亚语创建翻译。你需要这样做。 右键单击值文件夹 > 新建 > 值资源文件

enter image description here

现在将打开一个新窗口,您需要像这样填充它:

enter image description here

所以,让我们慢慢来,逐个领域。

  • 文件名:strings.xml - 与默认文件同名
  • 目录名:values-de-rDE - 这定义了带有德国国家代码的目录名,这就是编译器如何知道从哪个文件读取您定义的字符串。如果您不知道国家/地区代码,您可以简单地使用 Available qualifiers 并选择 Locale > From Language 部分选择“de: German” > From Specific Region 仅选择您想要的,在我的情况下我使用了“DE :德国”。这将自动生成与我上面所做的相同的目录名称:

enter image description here

现在您有了新的 strings.xml 文件,但它的右侧有一个附加标签,例如 (de-rDE)。现在在该文件中定义与默认相同的字符串 strings.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="Size">Größe</string>

</resources>

现在您可以看到我在此资源文件中没有为应用程序名称定义的字符串,您将收到警告。当您转到 default strings.xml 时,您会看到:

enter image description here

因此,请确保您在 strings.xml 文件中的所有文件中定义了相同的字符串。

我遵循了上面的所有内容,除了默认文件之外,还添加了更多克罗地亚语和英语的翻译。所以,现在我有了这个:

enter image description here

现在您可以使用我的函数 setLocale() 并在此行内提供国家/地区代码:

Locale locale;
locale = new Locale("de","DE");
Configuration config = new Configuration(activity.getBaseContext().getResources().getConfiguration());
Locale.setDefault(locale);
config.setLocale(locale);

activity.getBaseContext().getResources().updateConfiguration(config,activity.getBaseContext().getResources().getDisplayMetrics());

你可以看到第二个参数我只输入了“DE”而不是“rDE”。这会将区域设置设置为德语,并且您的应用将使用 strings.xml (de-rDE) 文件作为字符串资源。