вторник, 10 марта 2015 г.

Локализация приложений.

Разрабатывая приложения очень часто встает вопрос с локализацией его. Кто-то делает только английскую версию, кто-то добавляет русский язык, а кто-то делает сразу под множество языков.
Рассказывать, что нужно сразу все строковые данные выносить в файл ресурсов, если подразумевается в дальнейшем локализация на другие языки, думаю не кому не нужно. А вот с шрифтами в XNA возникает небольшая проблема. Стандартный файл шрифта, в XNA с расширением .spritefont имеет

<CharacterRegion>
    <Start>&#32;</Start>
    <End>&#126;</End>
</CharacterRegion>

и пока используются только символы из английского языка и без вывода специальных символов все хорошо, а дальше ждет сюрприз. В целом не чего сложного нет, как я уже писал в статье «Рисование дополнительных символов XNA» делается все довольно просто. Но вот с добавлением в свое приложение нескольких языков не все так просто, а по описанному выше способу это вообще титанический труд, я решил немного упростить этот вопрос для себя.

Перевод готов, файлы ресурсов готовы.
Пихать все символы в файл шрифта не стоит, лично я гружу только необходимый файл шрифта в зависимости от текущей культуры или культуры по умолчанию.
По мимо этого, нужно отредактировать файл .spritefont для определенной культуры.
Для начала, получаем строки из файла ресурсов и добавляем символы которых нету в ресурсах, в моем случае это цифры и спец символы, также у меня в коде строки могут принимать верхний и нижний регистр.

        private IEnumerable<string> GetStringsValue(CultureInfo culture)
        {
            var resourceSet = AppResources.ResourceManager.GetResourceSet(culture, true, true);
            
            var value = new List<string>();
            foreach (DictionaryEntry entry in resourceSet)
            {
                var resource = (string) entry.Value;
                value.Add(resource);

                value.Add(resource.ToLower());

                value.Add(resource.ToUpper());
            }

            value.Add("1234567890-=_+)(*&^%$#@!:;\"'/,.<>№[]{}~`");
            
            return value;

        }

После чего, для каждой поддерживаемой культуры формируем список символов и если возможно мы их объединяем.

        public void CreateRangeCharacters()
        {
            Debug.WriteLine("Start create range characters:");
            foreach (var cultureItem in _supportedCultures)
            {
                Debug.WriteLine("Culture start: " + (string.IsNullOrEmpty(cultureItem) ?
                    "default" : cultureItem));
                var culture = new CultureInfo("en");
                if (!string.IsNullOrEmpty(cultureItem))
                {
                    culture = new CultureInfo(cultureItem);
                } 
                
                var characters = new List<char>();
                
                var resources = GetStringsValue(culture);
                foreach (var resource in resources)
                {
                    foreach (var item in resource)
                    {
                        if (!characters.Contains(item))
                        {
                            characters.Add(item);
                        }
                    }
                }

                characters = characters.OrderBy(s => s).ToList();
                var array = string.Join(" ", characters.Select(PrintChar));
                Debug.WriteLine("Characters: ");
                Debug.WriteLine(array);

                /*Объединение*/
                Debug.WriteLine("    <CharacterRegions>");

                var oldValue = characters[0];

                var value = PrintChar(oldValue);

                var isFurther = false;

                for (var i = 1; i < characters.Count; i++)
                {
                    if (characters[i] - oldValue <= 1)
                    {
                        if (!isFurther)
                        {
                            Debug.WriteLine("      <CharacterRegion>");
                            Debug.WriteLine("        <Start>&#" + PrintChar(oldValue) + ";</Start>");
                            isFurther = true;
                        }
                    }
                    else
                    {
                        if (isFurther)
                        {
                            isFurther = false;
                            Debug.WriteLine("        <End>&#" + PrintChar(oldValue) + ";</End>");
                            Debug.WriteLine("      </CharacterRegion>");
                        }
                        else
                        {
                            if (!string.IsNullOrEmpty(value))
                            {
                                Debug.WriteLine("      <CharacterRegion>");
                                Debug.WriteLine("        <Start>&#" + value + ";</Start>");
                                Debug.WriteLine("        <End>&#" + value + ";</End>");
                                Debug.WriteLine("      </CharacterRegion>");
                            }
                        }
                        value = PrintChar(characters[i]);
                    }
                    oldValue = characters[i];
                }

                if (!string.IsNullOrEmpty(value))
                {
                    Debug.WriteLine("      <CharacterRegion>");
                    Debug.WriteLine("        <Start>&#" + value + ";</Start>");
                    Debug.WriteLine("        <End>&#" + value + ";</End>");
                    Debug.WriteLine("      </CharacterRegion>");
                }

                Debug.WriteLine("    </CharacterRegions>");

                Debug.WriteLine("Culture end!");
            }
            Debug.WriteLine("End create range characters!");
        }

        private static string PrintChar(char c)
        {
            var value = (int)c;
            return value.ToString(CultureInfo.InvariantCulture);

        }

А вот проверка уже получившихся файлов шрифтов, её следует запускать если были изменения.

        public void TestAllFonts(ContentManager contentManager)
        {
            Debug.WriteLine("Start test fonts: ");
            foreach (var cultureItem in _supportedCultures)
            {
                Debug.WriteLine("Culture start: " + (string.IsNullOrEmpty(cultureItem) ? "default" : cultureItem));

                var count = 0;
                foreach (var fontItem in _fonts)
                {
                    var fontPath = "Fonts/" + fontItem;

                    var culture = new CultureInfo("en");
                    if (!string.IsNullOrEmpty(cultureItem))
                    {
                        fontPath += "." + cultureItem;
                        culture = new CultureInfo(cultureItem);
                    }

                    var font = contentManager.Load<SpriteFont>(fontPath);

                    var resources = GetStringsValue(culture);
                    foreach (var resource in resources)
                    {
                        foreach (var item in resource)
                        {
                            if (!font.Characters.Contains(item))
                            {
                                Debug.WriteLine("Error!!! " + PrintChar(item));
                            }
                        }
                        //var size = font.MeasureString(resource);

                        count++;
                    }
                }
                Debug.WriteLine("Culture end count font: " + _fonts.Count + " resource count: " + count/_fonts.Count);
            }
            Debug.WriteLine("End test fonts!");

        }

Комментариев нет:

Отправить комментарий