본문 바로가기

[unity] 모듈 제작 : Localization Manager 제작

앤디가이 2022. 5. 30.

Unity에서 GoogleSheet를 활용하여 현지화 언어 변환 모듈인 Localization Manager Class를 만들어 보자.

 

1. 구글 시트 생성 및 테이블 작성

 - 구글 시트를 하나 생성한 후 간단한 테이블을 하나 만들어 준다.(구글시트 바로가기)

 - 테스트를 위한 테이블 구조는 아래와 같다.

Korean English Japanese
호랑이 =GOOGLETRANSLATE(A2,"Ko","En") =GOOGLETRANSLATE(B2,"Ko","ja")
사자 =GOOGLETRANSLATE(A3,"Ko","En") =GOOGLETRANSLATE(B3,"Ko","ja")
코끼리 =GOOGLETRANSLATE(A4,"Ko","En") =GOOGLETRANSLATE(B4,"Ko","ja")

 - 기본 베이스 언어는 한국어이며, 번역 텍스트인 영어와 일본어는 GOOGLETRANCLATE 함수를 이용하여, 자동 번역될 수 있도록 구성한다.

 - 기본 Key 값은 한국어가 기준이 된다.

 

2. 유니티 사전 준비

 - 스크립트 작성 전 Serialize Dictionary 를 사용하기 위해, 무료 에셋을 하나 추가해 주자.

 - SerializableDictionary 에셋 추가는 기존 팝업 시스템에서 추가했던 에셋과 동일하다.

2022.05.24 - [unity3d/Modules] - [unity] 모듈 제작 : 팝업 시스템 만들기(1)

 

[unity] 모듈 제작 : 팝업 시스템 만들기(1)

앱이나 게임에서 팝업은 상당히 자주 사용하는 요소이다. 공통 팝업을 모듈화하여 제작해 놓으면 다양한 씬에서 호출시 상당히 편리하다. 이번에는 빌더 패턴을 사용하여, 팝업 시스템(모듈)을

wonjuri.tistory.com

 - Assets에 Modules 폴더를 만들고 안에 Localization 폴더를 만들어 Prefabs와 Scripts 폴더를 만들어 준다.

Unity Localization
Unity Localization 폴더 구조

 

3. 유니티 스크립트 작성

 - Scripts 폴더 안에 LocalizationManager.cs Class와 LocalizationText.cs를 만들고, Editor 폴더를 만들어, LocalizationManagerEditor.cs의 에디터 클래스를 하나 만든다.

 - LocalizationManager.cs 클래스를 열어 아래와 같이 작성한다.

using System;
using System.Threading.Tasks;
using Cysharp.Threading.Tasks;
using UnityEngine;
using UnityEngine.Networking;

namespace Container.Localization
{

    [Serializable]
    public class StringStringDictionary : SerializableDictionary<string, string> { }

    [Serializable]
    public class LanguageDictionary : SerializableDictionary<string, StringStringDictionary> { }

    /// <summary>
    /// 현지화를 위한 언어팩 매니저 클래스.
    /// GoogleDoc을 파싱하여 사용.
    /// </summary>
    public class LocalizationManager : MonoBehaviour
    {

        protected string Language { get; private set; }

        public static LocalizationManager Instance { get; private set; }

        [SerializeField]
        private string langURL = "https://docs.google.com/spreadsheets/d/1LeDydivi55yGxns9u_PP59C7PLwcKqdAiL2EnCQ_Imk/export?format=tsv";

        [SerializeField]
        private LanguageDictionary Langs;

        void Awake()
        {
            Instance = this;
        }
        private void OnDestroy()
        {
            Instance = null;
        }

        private void Start()
        {
            //초기화는 시스템 기본 언어로 세팅한다.
            Language = Application.systemLanguage.ToString();
        }


        public void GetLocalizationText()
        {
            Langs.Clear();
            GetLanguage();
        }

        /// <summary>
        /// GoogleSheet에서 데이터 가져오기
        /// </summary>
        /// <returns></returns>
        private async Task GetLanguage()
        {
            UnityWebRequest request = UnityWebRequest.Get(langURL);
            var op = await request.SendWebRequest();
            SetLanguageList(op.downloadHandler.text);
        }

        /// <summary>
        /// 행, 열 분리하여 Dictionary에 데이터 입력 함수
        /// </summary>
        /// <param name="text"></param>
        private void SetLanguageList(string text)
        {
            string[] row = text.Split('\n');
            int rowSize = row.Length;
            int columnSize = row[0].Split('\t').Length;
            string[,] Sentence = new string[rowSize, columnSize];

            for (int i = 0; i < rowSize; i++)
            {
                string[] column = row[i].Split('\t');
                for (int j = 0; j < columnSize; j++) Sentence[i, j] = column[j];
            }

            Langs = new LanguageDictionary();
            for (int i = 1; i < rowSize; i++)
            {
                Langs.Add(Sentence[i, 0].TrimEnd(), new StringStringDictionary());

                for (int j = 0; j < columnSize; j++)
                {
                    Langs[Sentence[i, 0].TrimEnd()].Add(Sentence[0, j].TrimEnd(), Sentence[i, j]);
                }
            }
        }

        /// <summary>
        /// Key값으로 언어 검색
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public string GetText(string key)
        {
            if (Langs.ContainsKey(key))
            {
                if (Langs[key].ContainsKey(Language))
                {
                    return Langs[key][Language];
                }
                else
                {
                    //언어 키가 없을 경우, defalut로 영어 세팅.
                    if (Langs[key].ContainsKey("English"))
                    {
                        return Langs[key]["English"];
                    }
                }
            }
            return key;
        }
    }
}

 

 - 본인이 제작한 구글 시트 주소의 마지막 부분을 /edit#gid=0 에서 /export? format=tsv로 변경해줘야 한다.

 - LocalizationManagerEditor.cs 클래스는 아래와 같이 작성 한다.

 - 에디터에 버튼을 생성하고. 버튼을 누를 경우, LocalizationManager의 GetLocalizationText() 함수를 호출한다.

using UnityEngine;
using UnityEditor;

namespace Container.Localization
{
    [CustomEditor(typeof(LocalizationManager))]
    public class LocalizationManagerEditor : Editor
    {
        public override void OnInspectorGUI()
        {
            base.OnInspectorGUI();

            LocalizationManager _target = (LocalizationManager)target;

            if (GUILayout.Button("Get Localize Text"))
            {
                _target.GetLocalizationText();
                EditorUtility.SetDirty(_target);
            }
        }
    }
}

 

 - LocalizationText.cs는 UIText 컴포넌트와 같이 붙는 컴포넌트다.

 - UIText와 TextMeshPro Text를 지원한다.

 - 아래와 같이 작성해 준다.

using TMPro;
using UnityEngine;
using UnityEngine.UI;

namespace Container.Localization
{
    public class LocalizationText : MonoBehaviour
    {
        private void Start()
        {
            if (LocalizationManager.Instance != null)
            {
                string curStr = string.Empty;
                if(GetComponent<Text>())
                {
                    curStr = GetComponent<Text>().text;
                    GetComponent<Text>().text = LocalizationManager.Instance.GetText(curStr);
                }
                if(GetComponent<TextMeshProUGUI>())
                {
                    curStr = GetComponent<TextMeshProUGUI>().text;
                    GetComponent<TextMeshProUGUI>().text = LocalizationManager.Instance.GetText(curStr);
                }
            }
            else
            {
                Debug.LogWarning("LocalizationManager is null - Please check if there is any containers");
            }
        }
    }
}

 

4. Scene 구성

 - Modules라는 Scene을 만든 후, Modules GameObject와 LocalizationManager GameObject를 생성한다.

 - LocalizationManager의 GameObject에 LocalizationManager 스크립트는 붙여준다.

 - Lang URL을 넣어준다.(구글 스프레드 시트 주소이며 끝에는  //export? format=tsv

LocalizationManger
Localization Manager 연결

 

5. Test 방법

 - Get Localization Text 버튼을 눌러. 텍스트를 가져와 보자.

Localization Text
Localization Text 가져온 화면

 - Dictionary 형태로 잘 가져온 걸 확인할 수 있다.

 - 언어가 변환돼야 할 UIText 및 TextMeshProUGUI 게임 오브젝트에 LocalizationText 컴포넌트를 붙여준다.

 - 모바일에서 구동되면 핸드폰에서 SystemLanguage를 받아와 해당 언어로 변환해준다.

 - 현지화 언어를 받아오는 부분은 LocalizationManager.Instance.GetText(key값); 통해서 받아올 수 있다.

(LocalizationText.cs 스크립트 참고)

Localization Text Test Screen
테스트 완료 화면

 - 주의할 점은 프로젝트에서 사용 중인 폰트(. ttf, .otf)가 해당 언어를 지원해줘야 한다.

 

댓글