PDA

Просмотр полной версии : Нужен совет опытного флешера по мультиязычности.


searinox
10.06.2012, 00:35
Есть клиентское приложение, в нём необходимо реализовать мультиязычность (т.е. при выборе юзером определенного языка, во всех необходимых местах заменять тексты на дефалтном языке, на тексты на необходимом.
На данный момент существует такая система:
1. Есть ХML в котором содержатся тексты на необходимом языке. Например текстфилду который в кнопке выхода ("exit_btn_text") соответствует текст "Exit" ну и т.д.
2. Есть класс который парсит этот ХML и меняет текст в необходимом элементе интерфейса.
3. В управляющем классе замена языков происходит при загрузке приложения и при выборе юзером необходимого языка в опциях.

Вопрос следующего характера - как всю эту *****систему сделать более правильной, эргономичной и вообще как нормальные люди реализовывают такие вещи?

Psycho Tiger
10.06.2012, 01:10
Пара ключ-значение.
Например, можно сделать класс View, который содержит методы работы с тем, что может понадобиться вью.
Например, getResource, для загрузки динамического контента или getLocaleText, возвращающий текст сразу в нужной локали.
Т.е. локаль устанавливается где-то наверху, а элементы отображения делают что-то вроде:
//ru
super.getLocaleText('inventory.close'); //returns Закрыть инвентарь

//en
super.getLocaleText('inventory.close'); //returns Close inventory

searinox
10.06.2012, 01:33
То есть ты предлагаешь написать класс который самостоятельно разыменовывает ВСЕ элементы интерфейса, а сама именовка происходит для каждого элемента по его названию?
т.е. код метода getLocaleText() будет какой-то такой?

function getLocaleText(value:String):String{
switch (value){

case "accept_btn":
//вернуть необходимый текст
break;

case "cancel_btn":
//вернуть необходимый текст
break;

case "exit_btn":
//вернуть необходимый текст
break;

}
}

Psycho Tiger
10.06.2012, 09:25
Реализаций может быть много. Я бы хранил тексты в разных xml файлах, типа en.xml, ru.xml и т.далее, а сам getLocaleText бы возвращал значение из этого xml. Например, interface.close - это тег interface, внутри тег close.

Korchy
10.06.2012, 09:57
Я загружаю из базы список текстов. А в флешке запихиваю все это в массив и где нужно вызываю через класс-обертку над массивом.
Что-то вроде:
Button.Text = TextDictionary.Text(1);
В зависимости от выбранного пользователем языка в массиве в TextDictionary в первом элементе будет лежать или "Выход" для русского или "Exit" для английского языка.
Не знаю на сколько это правильно и экономично. Пока работает :)

kackbip
10.06.2012, 10:46
Обращение к элементам по номеру непоказательно. Лучше использовать говорящие индексы, константы или как psycho tiger написал - теги xml.

Inet_PC
10.06.2012, 12:37
Работает не трожь, не?

-De-
10.06.2012, 16:02
Да, по тегам из xml или ключам из Object вытягивать строку. Что ещё. Для больших приложений удобнее сделать двухуровневую систему, т.е.
function getLocaleText(group:String, key:String):String
использовать например
playButton.setText(getLocaleText("mainMenu", "play"));
Почему ещё это всплывает - имеет смысл привязывать строку локализацию не к слову, а к конкретному месту. Т.е. неправильно: слово "играть" имеет ключ play и везде, где встречается слово играть используется getLocaleText("play"). Правильно: для каждого места, где встречается слово "играть", делается отдельный ключ. Потому что на разных языках там могут быть разные слова и даже на одном языке могут быть различия в регистре ("ИГРАТЬ", "играть", "играть!" и "Играть").
Подумать насчет того, что смена языка вызывает перезапуск приложения (или делается только при самом старте). Потому что смена языка в любом месте в любой момент достаточно сложна в реализации и никому на самом деле не нужна.
Отдельная веселуха (особенно если есть смена языка в любой момент) - строки типа "Убито бобров 7 из 20, спасено деревьев - 7шт.". Не во всех языках удобно и вообще возможно, чтоб 7, 20 и 7 шли именно в таком порядке (лично мне такое встретилось в тексте просто "2 из 3", по-моему на тайском). Потому хороший вариант - написать функцию типа
function getLocaleTextParametrized(group:String, key:String, paramsArray:Array):String
Которая из строки типа "Убито бобров [1] из [2], спасено деревьев - [1]шт." делала нужную вызовом типа
getLocaleTextParametrized("statsMenu", "beaverProgress", [7, 20])

expl
10.06.2012, 19:30
getLocaleTextParametrized("statsMenu", "beaverProgress", [7, 20])
У нас такая штуковина, дабы не травмировать мозг запоминанием ключей, количества и назначения праметров для каждого ключа просто генерируется из таблицы с локализацией:


/** Какой-то текст с {parameter}-ом на ключ some_text */ //<-- это сгенерилось по дефолтному языку локализации -
//чтобы не отвлекаться, не смотреть что значит ключ
public static function some_text(parameter:String):String
{
return _values["some_text"].replace(/\{parameter\}/g, parameter);// Утрированно
}

Т.е набрал в редакторе в дной колонке ключ - в другой (соответствующей языку) текст - нажал ctl-s - у тебя добавились эти строчки в код и сгенерился файл для загрузки локализации.

Т.е. приведённый текст выглядел бы так:

Locale.statsMenu_beaverProgress(7, 20);


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

По поводу динамической замены языка - ни разу не приходилось делать (не требовалось), но возможны варианты:
1. Как в fl-компонентах - регистрируем прямо в локализаторе текстовые поля с ключом и при перезагрузке он их обновляет
2. Вручную подписываемся на локализатор во всех окошках и меняем все тексты при событии "изменился язык"
3. Делаем наследника TextField, который уже слушает изенения и сам себя меняет и используем его везде. А если сторонние компоененты используюся? - оборачивать?

Проблемы тут 2:
1. Как везде поменять текст с минимальным количеством кода
2. Размеры, вот незадача, тоже у полей будут меняться и ведь нужно реагировать - менять размеры окон и панелей, или дикий запас пространства оставлять

Вобщем, перечисленные 3 способа справляются с этими задачами с разным успехом.

Партизан
11.06.2012, 11:57
Локализация "на лету" у меня решается следующей схемой:
1. XML
<string id="str_id" ru="" en="" kz="" />
2. Функция в которой регистрируется str_id и текстфилд которому присваевается строка с текущей локалью. Все помещается в хэш-таблицу ключом которой выступает str_id, а значением соответственно текстфилд.
3. При смене локали всем зарегистрированным текстфилдам присваевается соответсвующая новой локали строка.

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

Wolsh
11.06.2012, 13:54
Мне такая схема кажется избыточной и недостаточно гибкой.
Гораздо приятней выглядит хранение локализаций в отдельных языковых файлах и один мастер-файл со списком существующих локализаций.
+ Маленький вес языковых файлов.
+ Меньше памяти съедается в рантайме.
+ Структура проста и красива.
+ Поддержка проста и удобна.
Вместо
<string id="str_id" ru="текст" en="text" sp="texto" />
будет
<str_id>текст</str_id>
Не нужно хранить совершенно ненужную информацию.
Не нужно устраивать динамический разбор присутствующих атрибутов или проверку их наличия; вообще как-то возиться с этой динамикой. Всегда есть только одно конкретное значение текста. При смене языка просто загружается новый файл и все значения заменяются.
По поводу размеров — больная тема)) Раньше у Адоба в русской версии Фотошопа были широченные панели, очень неприятно закрывавшие все поле действия, так что редактируя стиль какого-то слоя, ты не видел результатов, потому что окно редактирования стиля закрывало всю рабочую область)) В английской версии всё было компактненько. Недавно посмотрел CS6, в котором локализация меняется просто выбором языка в настройках. Даже при выборе английского панели все-равно остаются широкими, как для русского. Это ад.

Партизан
11.06.2012, 15:00
Гораздо приятней выглядит хранение локализаций в отдельных языковых файлах и один мастер-файл со списком существующих локализаций.
Не всегда так удобно. В моей схеме упор сделан на моментальную смену языка интерфейса в рантайме. Времени грузить нужный файл локализации нет. Хранить три файла в памяти считаю сомнительной выгодой. И поскольку строка по уникальному id возвращается, с целью уменьшения ошибок, считаю, лучше оставить id уникальным, не более чем в одном экземпляре.

expl
11.06.2012, 15:16
Недавно посмотрел CS6, в котором локализация меняется просто выбором языка в настройках. Даже при выборе английского панели все-равно остаются широкими, как для русского. Это ад.
Ну если уж Adobe на это забила, то куда уж нам, простым смертным.
Хотя, можно в паре критических окошек/панелей подписаться на событие изменения локализации и перевалидировать размер по этому событию.

Wolsh
11.06.2012, 16:40
Времени грузить нужный файл локализации нет.Не верю. Это не игровое действие в RTS. Пользователь подсознательно готов подождать 2-3 секунды "перевода", потому что это "подготовительный" процесс, а не основное его действие по использованию приложения.
Хранить три файла в памяти считаю сомнительной выгодой.Не предлагал.
лучше оставить id уникальнымНикто не заставляет Вас называть теги одинаково. Как раз предлагается избавиться от мультициклов поиска по XMLList'ам, ограничившись простым и быстрым доступом к XML.

iNils
11.06.2012, 16:40
Не всегда так удобно. В моей схеме упор сделан на моментальную смену языка интерфейса в рантайме. Времени грузить нужный файл локализации нет.
Смена языка довольно специфичная операция, чтобы для этого не было времени на загрузку)

Хотите еще частный случай? Бывает, что часть переводов не готова и вместо них используется дефолтный язык. Но переводы делаются. И когда приложение открыто сутками (не все браузеры закрывают и машину могут в спящий режим отправлять, то есть перегрузки приложение), при смене языке можно обновить перевод, если версии не совпадают.

А вообще, речь идет об оптимальном варианте, а не о единичном. У вас в примере 3 языка, а попробуйте 35 языков и не 20-50 слов, а 1000 слов или готовых фраз и предложений.

searinox
14.06.2012, 15:40
Всем спасибо. Очень интересные варианты как у Wolsh так и у Партизана, но изначально я использовал подход, который потом предложил Wolsh, и пока более или менее доволен. Еще раз спасибо за исчерпывающую информацию по этому вопросу.