Android13으로 업데이트를 진행하면서 시스템 설정-언어 항목에 앱 언어라는 카테고리가 생겼다.
Android13에서는 다국어를 지원하는 앱에 사용자가 원하는 언어로 기본 설정을 변경할 수 있는 기능을 도입한 것이다.
우리는 일반적인 앱과 같이 앱 내에서의 언어 변경 설정 항목을 만들 것이라 위의 항목이 변경되었다고 참고만 하면 될 것 같다.
app 단위 Gradle dependencies에서 compileSdk, appcompat 버전을 다음과 같이 변경한다.
(글 작성 기준 appcompat 1.6.0-rc01)
android {
compileSdk 33
.
.
.
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.6.0-rc01'
.
.
.
}
AppCompatDelegate에서 setApplicationLocales(), setApplicationLocales() 메서드를 사용하기 위해서 버전을 변경해 주어야 한다.
API 레벨33에서 추가된 steApplicationLocales()과 getApplicationLocales()는 다음과 같은 형태이다.
setApplicationLocales()의 형태는 아래 코드와 같다.
fun setApplicationLocales(locale: LocaleListCompat)
setApplicationLocales()
를 호출하여 호출 앱의 UI Locale을 locale값으로 변경시켜준다.
setApplicationLocales()
의 매개변수로 LocaleListCompat을 넘겨줘야한다.
locale값을 변경시켜주기 위해서 매개변수 LocaleListCompat을 넘겨주기 위해서 forLanguageTags()
메서드를 사용해야 하고 아래코드와 같은 형식이다.
fun forLanguageTags(list: String?): LocaleListCompat
매개변수로는 String형식을 받고 LocaleListCompat을 반환한다.
💻Ex)
val enLocale: LocaleListCompat = LocaleListCompat.forLanguageTags("en-US")
AppCompatDelegate.setApplicationLocales(enLocale)
getApplicationLocales()의 형태는 아래 코드와 같다.
fun getApplicationLoclaes(appPackageName: String)
getApplicationLocales()
를 호출하여 호출하는 앱의 UI Locale을 반환한다.
getApplicationLocales(appPackageName: String)
으로 appPackageName을 넣어주면 해당 패키지앱의 UI Locale값을 반환받을 수 있다.
💻Ex)
val getLocaleLanguage: LocaleListCompat = ApplicationDelegate.getApplicationLocales()
String.xml
파일에서 아래와 같이 <string>
태그로 사용 할 string을 작성한다.(필자는 영어, 한국어, 베트남어를 선택했다.)
‼️ Untranslatable을 체크하면 Default Value로 정의된 언어를 모든 언어에 적용하는 것으로 말그대로 번역하지 않는 것이다.
android:localeConfig
를 사용하여 앱에서 지원하는 언어리스트를 추가한다.
위에서 제작한 국가 별 string.xml
의 국가코드를 넣어준다.
일단 res폴더의 하위폴더인 xml폴더에 locales_config.xml을 생성한다.
res/xml/locales_config.xml
xml파일의 내용은 아래의 코드와 같다.
<?xml version="1.0" encoding="utf-8"?>
<locale-config xmlns:android="http://schemas.android.com/apk/res/android">
<locale android:name="en"/>
<locale android:name="ko"/>
<locale android:name="vi"/>
</locale-config>
언어의 이름은 언어 코드에 선택사항인 스크립트 코드, 지역 코드를 각각 하이폰(-)을 사용하여 결합한 후 작정한다.
언어 리스트가 완성되었으면 Manifest에서 만들어진 locales_config.xml을 가리키는 줄을 추가해야 한다.
<manifest>
...
<application
...
android:localeConfig="@xml/locales_config">
</application>
</manifest>
첫 실행 시 현재 설정 저장된 언어는 아무것도 없고, VI(베트남) 버튼 클릭으로 베트남어로 변경시켜 잘 저장되고 적용되는 모습을 볼 수 있다.
AppCompatDelegate 사용 시 주의사항으로 API 참조 문서에서는 getApplicationLocales, setApplicationLocales은 Activity의 OnCreate()가 호출된 이후에 사용해야 한다고 한다.
이러한 이슈는 (API33) 안드로이드 13에서 LocaleManager를 취득하는데 Context가 필요하게 되어 OnCreate() 이전에는 getApplicationLocales, setApplicationLocales의 실행이 정상적으로 작동하지 않는다고 한다.
⬇️ 실제로 Log를 찍어 getApplicationLocales
을 OnCreate 전/후를 비교해보았다.
super.OnCreate(savedInstanceState)
전에는 아무것도 반환받지 못한 반면 그 이후에는 최근에 내가 설정해둔 vi_VN(베트남어)를 잘 갖고 오는 것을 확인 할 수 있다.
‼️하지만 API32(Android12)이하에서는 OnCreate() 호출전 사용이 가능한데 그 이유는 AppCompatDelegate 내부에서 getApplicationLocales, setApplicationLocales의 반환 값을 멤버로 관리하고 있기 때문에 OnCreate() 호출전 정상 사용이 가능하다. 실제로 frameWork 측에 설정이 동기되는 것은 OnCreate()가 호출되었을 시기다.
그렇기 때문에 API32(Android12)이하 버전으로 사용하여 이슈를 대응하기도 하는데 진행해 보도록 하자.
위의 이슈와 같이 OnCreate() 호출전 사용을 해야 하는 경우를 위해 Android12이하에서의 구현을 해보도록 하자.
Android12 이하에서는 per-app language preferences의 기능이 존재하지 않아 AppCompat library를 사용하여 언어 설정의 기능을 구현할 수 있지만 앱이 종료되면 변경된 언어 설정이 리셋되기 때문에 앱 내부에서 변경된 언어 설정을 저장해둬야 한다.
일단 Manifest에 <aplication>
태그 안쪽에 아래와 같은 서비스를 만들어주자.
<service android:name="androidx.appcompat.app.AppLocalesMetadataHolderService"
android:enabled="false"
android:exported="false" >
<meta-data
android:name="autoStoreLocales"
android:value="true" />
</service>
Manifest에 AppLocalesMetadataHolderService
Service 항목을 추가하고 autoStoreLocales
값을 true
로 설정하고 andorid:enabled
를 false
로 설정하여 AndroidX에 언어 저장소를 처리하도록 지시한다. 다만 이렇게 autoStoreLocales
값을 true
로 설정하면 기본 스레드에서 블로킹 읽기가 방생하고, StrictMode diskRead/Write 위반이 발생할 수 있다. 하지만 지금 테스트 앱은 자체 언어 설정 기능을 갖고 있지 않았고 기존의 데이터가 인계되는 경우도 고려할 필요가 없어 이대로 진행한다.
‼️만약 자체 저장소를 처리하고 있으면 autoStoreLocales
값을 fasle
로 설정하거나 Manifest에서 항목을 생략하여 처리한다.
이 경우는 Activity의 OnCreate()
전에 저장된 언어를 제공해야함으로AppCompatDelegate.setApplicationLocales()
를 호출해 줘야 한다.
위의 작업은 Android 13이상에서는 실행되지 않도록 제어해 줘야 하고 setApplicationLocales()
동작시 자체 저장소에도 설정을 저장해 주어야 한다.
실행을 제어하는 이유는 per-app language preferences로 언어 설정을 저장하고 있음으로 초기화할 필요가 없고, 위에서 설명했듯이 OnCreate()
전에 호출해도 정상적으로 기능하지 않기 때문이다.
구현은 위에 설명한 것과 같음으로 설명은 생략하고 위와 같이 사용해 보면 잘 동작하는 것을 알 수 있다.
⬇️ 위에서 설명한 OnCreate() 호출전 getApplicationLocales
를 로그로 찍어 보았다.
시스템 언어로 재설정을 하고 싶다면 Manifest에서 android:localeCofig
를 삭제하는 간단한 방법도 있지만 앱단에서 해결하고 싶다면 LocaleListCompat.getEmptyLocaleList()
또는 LocaleList.getEmptyLocaleList()
를 사용하여 앱 언어를 시스템 언어로 재설정하는 것을 공식 문서에서는 추천한다.
내 개인적 생각으로는 Locale().getDefault()
로 시스템 Locale값을 갖고 와서 적용해 주는 방법도 좋을 것 같다.
실습나온 회사에서 글로벌 앱 프로젝트를 진행한 적이 있어서 언어 변경 기능에 대해 많이 고민하고 찾아보고 노력했었다. 하지만 Android13 업데이트 문서를 읽고 당황했다. 나는 createConfigurationContext
를 활용하여 언어 변경 기능을 구현하기 위해 많은 시간을 투자했었기에 이렇게 간단하게 사용할 수 있는 라이브러리를 왜 이제 제공해 주나 싶었다.
물론 여러 방법을 알면 좋기 때문에 얻은 건 많지만 다시 사용하고 싶지는 않다.
시간이 난다면 전에 개발한 기능 GitHub 링크와 로그를 비교한 테스트 프로젝트를 업로드하겠다.
😭 초보 주니어 안드로이드 개발자가 남긴 글이니 이상하다 싶으면 공식 문서를 찾아보세요!~ 가르쳐주기 위한 댓글은 언제나 환영입니다.
Android Developer: https://developer.android.com/guide/topics/resources/app-languages?hl=ko#sample-config
언어변경 혼자 끙끙 앓고 있었는데 글보고 방향이 좀 잡히네요 ㅠㅠㅠㅠ 진짜 너무 도움됐어요 감사합니다!!