首页 > 解决方案 > 如何让 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, 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;
    }

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

        }




}

标签: androidmultilingual

解决方案


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

  • 语言名称(例如英语)
  • 语言代码(例如 en)
  • 语言脚本(例如美国)

这就是我这样做的方式:

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.xml基于language_codeand language_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>

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

在此处输入图像描述

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

在此处输入图像描述

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

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

在此处输入图像描述

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

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

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

</resources>

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

在此处输入图像描述

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

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

在此处输入图像描述

现在您可以使用我的功能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)文件作为字符串资源。


推荐阅读