본문 바로가기

안드로이드/코드

[안드로이드] 앱 내부에서 언어 설정 변경하기 (feat.Spinner)

반응형

 

 

 

 

 

 

 

 

locale1

 

여러 국가의 언어를 사용하는 어플을 제작하기 위해서 여러 가지 방법이 있지만 앱 내부에서 설정을 만들고 싶으실 때 참고하시면 좋을 것 같습니다.

저는 Spinner를 사용해서 언어를 선택하고 원하는 언어로 설정되게 하는 예제를 만들어보겠습니다.

 

 

1. activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <Spinner
        android:id="@+id/spinner"
        android:layout_marginTop="50dp"
        android:layout_marginBottom="50dp"
        android:layout_gravity="center"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:spinnerMode="dropdown"
        app:layout_constraintBottom_toTopOf="@+id/textView" />


    <TextView
        android:id="@+id/textView"
        android:gravity="center"
        android:textColor="@android:color/black"
        android:textSize="20sp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>


</LinearLayout>

 

android:spinnerMode="dropdown"

스피너의 아이템들이 밑으로 바로 출력되는 방식입니다.

 

locale2

 

android:spinnerMode="dialog"

스피너의 아이템들이 다이얼로그 형식으로 출력 되는 방식입니다.

 

locale3

 

 

2. strings.xml

<resources>
    <string name="app_name">spinner</string>
    <string name="hello">안녕</string>
    <string name="korean">한국어</string>
    <string name="english">영어</string>
    <string name="chinese">중국어</string>
</resources>

 

영어, 중국어도 똑같이 추가해줍니다.

다른 국가의 언어를 추가하는 방식은 링크를 참고해주세요

 

 

3. MainActivity.java

package com.everyshare.spinner;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.AssetManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Build;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.Locale;

public class MainActivity extends AppCompatActivity {
    TextView textView;
    Spinner spinner;
    SharedPreferences sharedPreferences;
    String locale;
    int locale_number;
    ArrayList<String> locales;
    ArrayAdapter adapter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);



        sharedPreferences = getSharedPreferences("shared",MODE_PRIVATE);

        //버전 확인후 sharedpreferences에 locale키 값의 value값을 가져옵니다.
        //값이 없을 경우 기본언어 설정
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            locale = sharedPreferences.getString("locale",getResources().getConfiguration().getLocales().get(0).getLanguage());
        }else{
            locale = sharedPreferences.getString("locale",Resources.getSystem().getConfiguration().locale.getLanguage());
        }



        //스피너 기본 선택값을 주기 위해서 해당 언어의 순서에 맞게 int값을 준비해줍니다.
        switch (locale){
            case "ko":{
                locale_number = 0;
                break;
            }
            case "en":{
                locale_number = 1;
                break;
            }

            case "zh":{
                locale_number = 2;
            }
        }

        textView = findViewById(R.id.textView);

        //스피너로 설정한 언어에 맞는 언어로 TextView에 텍스트를 넣어줍니다.
        textView.setText(getStringByLocal(this,R.string.hello,locale));

        spinner = findViewById(R.id.spinner);

        locales = new ArrayList<>();

        //strings.xml에 있는 언어 가져와서 리스트에 추가
        locales.add(getStringByLocal(this,R.string.korean,locale));
        locales.add(getStringByLocal(this,R.string.english,locale));
        locales.add(getStringByLocal(this,R.string.chinese,locale));


        adapter = new ArrayAdapter(this, android.R.layout.simple_spinner_dropdown_item, locales);


        spinner.setAdapter(adapter);
        spinner.setSelection(locale_number);


        spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                //선택한 아이템의 포지션이 현재 설정되어있는 언어의 포지션이 아닐 경우
                if(position != locale_number){

                    switch (position){
                        case 0:{
                            locale = "ko";
                            break;
                        }
                        case 1:{
                            locale = "en";
                            break;
                        }
                        case 2:{
                            locale = "zh";
                            break;
                        }
                    }

                    //sharedpreferences를 생성
                    SharedPreferences.Editor editor = sharedPreferences.edit();

                    //sharedpreferences 안에 선택한 locale값 넣기
                    editor.putString("locale",locale);

                    //저장
                    editor.commit();

                    //어플 재시작
                    Intent intent = getBaseContext().getPackageManager()
                            .getLaunchIntentForPackage(getBaseContext().getPackageName());
                    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    finish();
                    startActivity(intent);

                }
            }


            //아무것도 선택하지 않았을 경우
            @Override
            public void onNothingSelected(AdapterView<?> parent) {
                spinner.setSelection(locale_number);
            }
        });
    }


    //선택한 언어에 맞는 String값을 반환합니다.
    @NonNull
    public static String getStringByLocal(Activity context, int resId, String locale) {
        //버전에 따라서 언어를 설정해주는 방식이 다르기 때문에 분류해서 사용합니다.
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1)
            return getStringByLocalPlus17(context, resId, locale);
        else
            return getStringByLocalBefore17(context, resId, locale);
    }

    //젤리빈 버전 이상일 경우
    @NonNull
    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
    private static String getStringByLocalPlus17(Activity context, int resId, String locale) {
        Configuration configuration = new Configuration(context.getResources().getConfiguration());
        configuration.setLocale(new Locale(locale));
        return context.createConfigurationContext(configuration).getResources().getString(resId);
    }


    //젤리빈 버전 이하일 경우
    private static String getStringByLocalBefore17(Context context, int resId, String language) {
        Resources currentResources = context.getResources();
        AssetManager assets = currentResources.getAssets();
        DisplayMetrics metrics = currentResources.getDisplayMetrics();
        Configuration config = new Configuration(currentResources.getConfiguration());
        Locale locale = new Locale(language);
        Locale.setDefault(locale);
        config.locale = locale;
        /*
         * Note: This (temporarily) changes the devices locale! TODO find a
         * better way to get the string in the specific locale
         */
        Resources defaultLocaleResources = new Resources(assets, metrics, config);
        String string = defaultLocaleResources.getString(resId);
        // Restore device-specific locale
        new Resources(assets, metrics, currentResources.getConfiguration());
        return string;
    }
}

 

스피너의 레이아웃은 안드로이드에서 기본으로 제공되는 레이아웃을 사용하도록 설정했습니다.

 

참고하실 부분은 onNothingSelected는 스피너를 선택한 후에 아이템을 선택하지 않고 다른 뷰를 터치하거나 뒤로 가기 등의 이벤트가 발생했을 때 작동하는 함수라고 생각하시면 될 것 같습니다.

 

저는 원래 기본값을 넣어주도록 코딩했습니다. 

 

getStringBylocal 함수는 링크를 참고해서 만들었습니다.

 

반응형