Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   ActionScript 3.0 (http://www.flasher.ru/forum/forumdisplay.php?f=83)
-   -   Заложить основу мультиязычности (http://www.flasher.ru/forum/showthread.php?t=214576)

Appleman 27.09.2017 01:22

Заложить основу мультиязычности
 
Вопрос к опытным коллегам (хотя какой я вам пока коллега :confused:).

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

На концептуальном уровне всё вроде бы понятно. Будущая многоязычность моего приложения основывается на следующих принципах:
1. Никаких жёстко заданных текстов внутри кода. Только идентификаторы, по которым будут подбираться текста на выбранном пользователем языке;
2. Все тексты живут в неких "накопителях". У меня пока это "классы-хранители" со статическими методами и переменными типа Object, хранящими тексты по строковым идентификаторам. В дальнейшем буду думать, что с ними делать: менять на XML или ещё что-нибудь, пока это представляется несущественным;
3. Между игровой механикой и готовыми текстами, живущими в классах-хранителях, должна быть ещё отдельная языковая логика. Например, для русского языка требуется подбирать слова в нужных падежах, а в английском - нет. Таким образом, просто выдёргивать по одним и тем же идентификаторам строковые переменные из идентичных хэшей точно не получится. Значит между игровой механикой и "складом" строковых переменных должны быть ещё некие "посредники", осуществляющие эту самую языковую логику.

Соответственно, по первому пункту вопросов особенно нет, всё ясно. Со вторым пока ничего не ясно, было бы интересно узнать для общего развития, но не к спеху. А вот по третьему огромная просьба помочь.

Стал прикидывать, как сделать... Это может быть один класс для всех языков, но запускающий разные методы, в зависимости от выбранного языка. Или базовый класс и классы-наследники для каждого из поддерживаемых языков, переопределяющие методы. Может быть вообще пространства имён или ещё какая-нибудь экзотика. Пока ограничился тем, что отделил игровую механику от подбора текстов, плюс создал пакет language, куда скинул эти самые классы-хранители и классы-"подбиратели" текстов.

В общем виде вопрос такой. О чём следует подумать и что сделать с самого начала разработки, чтобы заложить хорошую основу для будущей многоязычности? Наверняка есть общая практика и отработанные решения. Может ссылочку подбросите, сам ничего путного не нашёл, увы. Заранее спасибо.

undefined 27.09.2017 02:34

Мне кажется ,ты сам себе проблему придумываешь в 99% случаев форма слов известна заранее и не меняется. Максимум для числительных две формы задавать надо:lives_single/lives_plural. Но оно и для англ. локали требуется.
Только если ты не делаешь супер рпг, которая должна будет генерить диалоги на лету.

caseyryan 27.09.2017 07:24

Цитата:

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

Appleman 27.09.2017 15:55

Цитата:

Сообщение от undefined (Сообщение 1202130)
Мне кажется ,ты сам себе проблему придумываешь в 99% случаев форма слов известна заранее и не меняется. Только если ты не делаешь супер рпг, которая должна будет генерить диалоги на лету.

Супер-не супер, но до фига текста собирается из кусков по ситуации, где, например, фигурируют собственные имена персонажей, которые должны подставляться из переменных. Как тут без падежей обойтись для русского языка?

Цитата:

конечно есть, гугли по запросу i18n
О! Спасибо. Кто бы мог подумать, что это такой хренью обзовут! Сам бы не догадался.

caseyryan 27.09.2017 19:44

это просто сокращение от internationalization. i и n первая и последняя буквы, а 18 - количество букв между ними. Есть еще l10n - localization

Nooob 29.09.2017 00:52

используй по возможности текста со всеми комбинациями, если есть огромные комбинаций (невозможно обработать вручную) используй выражения в которых постановочные слова используют в именительном падеже
вместо: Изготовьте %item%, чтобы выполнить задание
так: Изготовьте предмет %item%, чтобы выполнить задание
практика показывает что квадратичные комбинации не составляют проблем для описания каждой, зато выражение более лаконичны

Appleman 29.09.2017 10:20

Цитата:

практика показывает что квадратичные комбинации не составляют проблем для описания каждой, зато выражение более лаконичны
Чего-то я с квадратичными комбинациями не понял, о чём речь. Можешь пояснить последнюю фразу, пожалуйста?

Appleman 04.10.2017 10:52

Друзья, хочу обновить тему. Почитал я то, что нашёл на родном языке по i18n, спасибо за наводку, но в подавляющем большинстве статей описываются лишь общие подходы. Удалось почерпнуть оттуда, что, например, помимо непосредственно языка не следует забывать о форматах дат и времени, валюте и т.п. Это всё прекрасно и понятно.

Из своих собственных изысканий пока пришёл к тому, что как и планировал изначально, полностью отделил игровую механику от текстов и вообще языка, создал классы-хранители с ассоциативными массивами, забитыми текстом, а между ними добавил классы-посредники с языковой логикой. Причём все обращения к классам-хранителям строятся с помощью методов с идентичной сигнатурой: Id-шник на входе, переменная типа String на выходе - ничего лишнего.

Вопросы у меня следующие:
1. Насколько я разобрался (пока только теоретически и в самых общих чертах) в интерфейсах, есть такое ощущение, что использование интерфейсов в частности помогает стандартизировать обмен информацией с классами в программе. Я правильно представляю, что мой пример с языком - это тот случай, где было бы оправдано внедрение единого интерфейса для всех классов, работающих с хранением и выдачей текстов? Или для разработчика-одиночки это будет ненужным усложнением (типа, держать в голове установленный самому для себя стандарт и не париться)?

2. Всё равно остаётся много вопросов не по общей организации (что нужно интернационализировать), а по практической реализации мультиязычности в приложении. Кто делал, поделитесь опытом плиз или кусок кода приведите, если не секрет. Мучаюсь выбором, то ли оставлять единые классы с языковой логикой, но внутри их писать отдельные методы для каждого языка, то ли отдельные классы делать... То же самое и с хранением инфо о выбранном языке: просто в виде идентификатора в каком-нибудь классе типа Config, или в виде пространства имён, чтобы потом писать методы с одинаковыми названиями, но вызывать с помощью пространства имён нужную версию. В общем, просьба помочь советом.

3. Есть понимание, что как уже было замечено многими коллегами здесь на форуме, хранить тексты в коде - не дело. Действительно, не дело. Думаю переходить к XML, чтобы и дополнительные языки подключались. А вот как это практически сделать, не понимаю? От слова совсем. Вопрос загрузки и чтения данных из файла XML не стоит - это много где описано с примерами. А вот как создавать сам файл и набивать туда данные? Руками это не делается. Значит, нужно писать отдельную программу или дополнительные классы в своей программе, которая будет из моих статических таблиц с идентификаторами "забивать" строковые значения в XML. Так? А если потом ещё какие-то текста добавить нужно... Совсем нет понимания технологии такой работы.

Wolsh 04.10.2017 21:12

1>>Интерфейсы могут быть реализованы только экземплярами. Другими словами, статические методы интерфейсами не регламентируются.

2>>Пространства имен не дадут тебе возможности добавлять языки, не переписывая код. Ведь для нового языка тебе придется добавить пространство имен и соответствующие методы. Надо абстрагировать систему так, чтобы программе было совершенно фиолетово, какой язык.
Ты вот приводил пример, что в английском нет падежей. Ну так это значит, что все замены будут однотипные в именительном падеже. То есть везде в тексте будет $n0, и не будет $n1...$n5. А в массиве замен будет просто одно имя John, а не Маша в шести падежах. И поэтому один и тот же алгоритм сможет обрабатывать текст и на русском и на английском. Почему? Потому что разница только в данных, и если данные Текст соответствуют данным Замены, то никаких проблем не будет. Такой же степени абстракции кода надо добиться во всех других случаях. Например, формат даты и времени тоже можно как-то единообразно зашифровать и передавать в файле языковых данных, например там <dataFormat>DD.MM.YYYY</dataFormat>. И написать парсер (мне кажется это не так уж сложно) который будет в рантайме форматировать дату-время под заданный формат. То есть постоянный код, не заменяемый с языком, способный отформатировать дату по заданному шаблону (а вариантов форматов, мягко говоря, совсем немного).

3>>Не совсем понял, что значит "руками это не делается"? При чем тут "статические таблицы"? А их кто писал? Не руками? Как-то вообще непонятно, что ты имеешь ввиду.
Я не делал текстовых квестов. Возможность смены языков я делал для приложения типа хранилища и редактора записок, то есть там смена языка только в интерфейсе. Для каждой фразы имеется идентификационный номер. В коде, когда надо вывести текст, идет обращение к классу Language и вызывается его статический метод getText(id:uint):String. Этот класс в начале программы загружает XML, в котором все фразы хранятся со своими идентификаторами, например в Eng.xml так:
<phrase id="123684">The File $&fileName is broken.</phrase>
а в Rus.xml так:
<phrase id="123684">Файл $&fileName поврежден.</phrase>

Как программа узнает, какой файл языка загрузить и применять? Его название хранит config.xml, который программа загружает самым первым и из него берет пути к остальным настроечным файлам — теме оформления интерфейса, истории открывавшихся файлов, файлу языка.

То есть, по-порядку:
программа загружает config.xml
в нем указано <language>Rus</language>
программа активирует класс Language, передавая ему путь загрузки "Rus.xml"
Language открывает этот файл и считывает его в объект XML
программа двигается дальше, отрисовывает интерфейс, периодически обращаясь к Language.getText(#) —
ей не надо ничего знать о том, какой там на дворе язык: Language даст ей фразу на нужном языке и дату/время в нужном формате (шаблон русского формата указан в Rus.xml)

Appleman 05.10.2017 10:25

Цитата:

Сообщение от Wolsh (Сообщение 1202235)
1>>Интерфейсы могут быть реализованы только экземплярами. Другими словами, статические методы интерфейсами не регламентируются.

Спасибо, понятно. Вопрос пока снят.


Цитата:

Надо абстрагировать систему так, чтобы программе было совершенно фиолетово, какой язык. Ты вот приводил пример, что в английском нет падежей. Ну так это значит, что все замены будут однотипные в именительном падеже. То есть везде в тексте будет $n0, и не будет $n1...$n5. А в массиве замен будет просто одно имя John, а не Маша в шести падежах. И поэтому один и тот же алгоритм сможет обрабатывать текст и на русском и на английском.
Угу, логично. Действительно, я смогу добиться единого алгоритма для разных языков. Вот теперь всё в голове более-менее выстроилось в единую картинку. Спасибо, thanks и merci :)

Цитата:

3>>Не совсем понял, что значит "руками это не делается"? При чем тут "статические таблицы"? А их кто писал? Не руками? Как-то вообще непонятно, что ты имеешь ввиду.
Я имел в виду не само содержание, т.е. фразы, а именно разметку файла XML: все эти теги разных уровней, открывающие, закрывающие и т.п. Поэтому я и спрашиваю, какие есть инструменты для формирования файлов XML для будущего использования.

Цитата:

Как программа узнает, какой файл языка загрузить и применять? Его название хранит config.xml, который программа загружает самым первым и из него берет пути к остальным настроечным файлам — теме оформления интерфейса, истории открывавшихся файлов, файлу языка.
С папками для языков, содержащих файлы xml с идентичными названиями, всё ясно. А сам файл config.xml будет храниться где-то вместе с готовым приложением. Есть какие-либо правила по его размещению? Пока ведь у меня в проекте только то, что сам Flash создал: папка src с классами, bin и ещё чего-то. И загружаем мы этот конфиг прямо на старте программы, скорее всего, создав для этого отдельный класс со статическими методами? А если пользователь что-то меняет в конфиге, то изменяем записи в этом самом config.xml. верно?

Wolsh 05.10.2017 13:38

В моем случае речь шла об Air-приложении (тебе тоже стоит копать в Air)
В Air после установки приложения автоматически создаются директории, связанные с этим приложением.
Есть "пользовательская" директория в "Моих документах", есть папка в которую установилась программа (но файлы в ней не могут быть изменены) и папка для специальных файлов программы, которые можно перезаписывать — в ней соответственно и размещается config.xml и дополнительные папки для языков и тем.
Пользователь, конечно, "меняет" не в конфиге, ему программа предоставляет интерфейс для настроек, где можно выбрать тему и язык. И тогда да, программа перезаписывает измененный конфиг — на выходе из приложения.
А вот языковые файлы придется менять вручную, открыв например русский и переводя каждую фразу на нужный язык, затем сохранить с новым именем, открыть лежащий в папке языков файл со списком доступных языков и внести в него этот новый язык (чтобы программа могла его предложить пользователю).

Appleman 05.10.2017 14:05

Цитата:

Сообщение от Wolsh (Сообщение 1202237)
В моем случае речь шла об Air-приложении (тебе тоже стоит копать в Air)

Да, почитал, скорее всего, так и надо делать. Что порекомендуешь, сразу пересоздать проект как проект AIR (я во flashDevelop работаю) или пока спокойно разрабатывать, а потом уже по готовности компилировать для AIR?

Цитата:

А вот языковые файлы придется менять вручную, открыв например русский и переводя каждую фразу на нужный язык, затем сохранить с новым именем, открыть лежащий в папке языков файл со списком доступных языков и внести в него этот новый язык (чтобы программа могла его предложить пользователю).
Это само собой. Я о другом спрашивал. Самый первый исходный файл XML (в моём случае с русским языком) полностью вручную верстать? Думал, кто-нибудь порекомендует удобную оболочку для формирования xml-файлов. Сам поищу...

undefined 05.10.2017 14:33

XML дюже избыточен.Большие конфиги лучше хранить в JSON, который можно генерить прямо из кода.

Wolsh 05.10.2017 20:41

Цитата:

Думал, кто-нибудь порекомендует удобную оболочку для формирования xml-файлов. Сам поищу...
ну, я так и не понял, чего ты хочешь от этой оболочки? Кнопку "сделать всё хорошо"? Что она должна уметь делать? Закрывающий тэг ставить? Так это и ФД умеет прекрасно.

undefined, чем это лучше, хранить на диске конфиг в JSON? И фраза как-то странно построена, как будто XML нельзя "генерить прямо из кода".

undefined 05.10.2017 20:58

Цитата:

чем это лучше, хранить на диске конфиг в JSON?.
Цитата:

XML дюже избыточен
Одни тэги на большом конфиге неслабо откушают,плюс читается json легче и привычнее.
Цитата:

И фраза как-то странно построена, как будто XML нельзя "генерить прямо из кода"
Имеется в виду что можно и в коде и в конфигах иметь одну и ту же структуру,что удобно

Appleman 10.10.2017 16:27

Цитата:

Сообщение от Wolsh (Сообщение 1202237)
В Air после установки приложения автоматически создаются директории, связанные с этим приложением. ...и папка для специальных файлов программы, которые можно перезаписывать — в ней соответственно и размещается config.xml и дополнительные папки для языков и тем.

Есть какое-то общепринятое имя для этой папки?

Цитата:

А вот языковые файлы придется менять вручную
Вопрос по этим самым языковым файлам. Почитал вдумчиво, как работает XML в AS3. Если я правильно понял, то переменная типа XMLList фактически "затягивает" всё иерархическое дерево из файла, начиная с некоего указанного уровня. А дальше с нею можно гибко работать, используя разнообразные методы класса XMLList. Интересует следующее. В ситуации большого количества слов и фраз, как лучше организовать их хранение и загрузку?

Мне пока видятся такие принципиальные варианты. Можно сделать один файл, загрузить его целиком в переменную прямо при запуске приложения и дальше работать только с ней, не обращаясь более у исходному файлу. Или наоборот для получения нужной фразы каждый раз обращаться к файлу-хранилищу по новой. Или сделать некий промежуточный вариант, добавив в иерархию XML-файла дополнительный уровень для, например, каких-то относительно независимых кусков игрового процесса (отдельный пакет фраз для меню, для каждого квеста, встроенных мини-игр и т.п.), чтобы обращаться к файлу при запуске каждого "куска", и забирать только тексты, связанные с ним.

Спасибо.

GBee 11.10.2017 00:40

Я бы не работал напрямую с хмл, перегнал бы все в словарь какой-нить [ключ]-[значение] и тягал бы из него по мере надобности.

Добавлено через 5 минут
Цитата:

плюс читается json легче и привычнее.
Глазами? При всей любви к жсону - он нечитаем без инструментов. Хотя хмл без форматирования тоже ад.

illuzor 11.10.2017 00:48

Appleman, xml уже мало кто использует. Json намного удобней и компактней, и работать с ним проще. В as3 есть нативная серилизация\десирилизация json.


Как раз с json вот это:
Цитата:

Я бы не работал напрямую с хмл, перегнал бы все в словарь какой-нить [ключ]-[значение] и тягал бы из него по мере надобности.
делается одной строчкой кода, а для xml нужно городить свой парсер.

GBee 11.10.2017 00:58

Цитата:

Сообщение от illuzor (Сообщение 1202319)
Appleman, xml уже мало кто использует. Json намного удобней и компактней, и работать с ним проще. В as3 есть нативная серилизация\десирилизация json.


Как раз с json вот это:делается одной строчкой кода, а для xml нужно городить свой парсер.

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

Wolsh 11.10.2017 13:40

Цитата:

Есть какое-то общепринятое имя для этой папки?
Имя и расположение зависит от системы (в винде одно, в макОС другое). В самом AIR будет доступна ссылка (путь) как свойство класса File.
Цитата:

Если я правильно понял, то переменная типа XMLList фактически "затягивает" всё иерархическое дерево из файла, начиная с некоего указанного уровня.
Не так. XMLList не имеет никакой иерархии, это одномерная коллекция (список) ссылок на элементы XML, отвечающие заданным требованиям. В практическом смысле XMLList является "результатами поиска" в документе XML элементов/узлов с определенными параметрами. Важно понимать, что лист содержит ССЫЛКИ на элементы, а не их копии; соответственно всё, что ты будешь делать с элементами листа, на самом деле ты будешь делать с элементами отцовского XML. Эти самые параметры "поиска" (в AS3 реализован синтаксис е4х) настолько разнообразны, что можно "выловить" любой элемент/ы по любому признаку, от места в иерархии до собственных свойств. (с JSON работать не приходилось, не уверен что там есть подобный е4х инструмент)

Appleman 11.10.2017 18:57

Цитата:

Сообщение от GBee (Сообщение 1202317)
Я бы не работал напрямую с хмл, перегнал бы все в словарь какой-нить [ключ]-[значение] и тягал бы из него по мере надобности.

Имеется в виду некий объект, создаваемый непосредственно в программе? То есть при запуске формировать словарь из файла с нужным языком, а потом уже к нему по ключам обращаться?

Цитата:

Если словарик не типизирован, то да. На самом деле в качестве значения может быть более сложный объект, который там содержит заодно окончания слов всякие для разных чисел и т.п. Тут уж фантазия может разойтись.
А есть примеры использования? Я раньше с JSON не сталкивался, сейчас впервые посмотрел на него. Действительно, выглядит аккуратнее и компактнее, по сравнению с XML. Но у последнего огромное преимущество - все механизмы работы с ним разжёваны вдоль и поперёк :)

ZackMercury 11.10.2017 19:25

https://pp.userapi.com/c639118/v6391...ff9YSWSxKE.jpg
А я не стесняюсь работать напрямую с XML.
(здесь названия элементов соответствуют id элементов на странице, и скрипт затем подставляет в них содержимое)

Appleman 12.10.2017 18:34

Потихоньку дополз до реализации некоторых моментов, описанных уважаемым wolsh. Теперь прошу пояснить кое-что по мелочи.

Цитата:

Сообщение от Wolsh (Сообщение 1202235)
Для каждой фразы имеется идентификационный номер. В коде, когда надо вывести текст, идет обращение к классу Language и вызывается его статический метод getText(id:uint):String. Этот класс в начале программы загружает XML, в котором все фразы хранятся со своими идентификаторами

Цитата:

Language открывает этот файл и считывает его в объект XML
программа двигается дальше, отрисовывает интерфейс, периодически обращаясь к Language.getText(#)
Чего-то я туплю. Как заставить класс Language загрузить в начале программы фразы из XML и обеспечить возможность обращаться к ним периодически в рантайме? Я правильно понимаю, что если на старте программы (или после смены языка пользователем) мы вызовем статический метод getPhraseBase класса Language с передачей туда id языка из конфига, он загрузит содержимое XML файла на нужном языке
и сохранит в статическую переменную, то в дальнейшем мы всегда сможем обратиться к этой переменной за фразой? Или нет?

Цитата:

3>>Не совсем понял, что значит "руками это не делается"? При чем тут "статические таблицы"? А их кто писал? Не руками? Как-то вообще непонятно, что ты имеешь ввиду.
Я имею в виду, что если к примеру идентификатор каждой фразы формируется из значений каких-то переменных в программе (в частности, уже несколько раз упоминавшейся нами вариант 'наименование свойства + идентификатор пола персонажа as String' для определения массива расшифровок значения данного свойства), то файл XML с этими самыми расшифровками было бы сподручнее и, что важнее, гораздо надёжнее сгенерировать, чем писать вручную, рискуя допустить очепятку. Благо нужные идентификаторы и слова/фразы уже есть в статической таблице Object.

Wolsh 12.10.2017 21:28

Цитата:

Как заставить класс Language загрузить в начале программы фразы из XML и обеспечить возможность обращаться к ним периодически в рантайме?
Да проще простого. Поскольку класс "статический" (в смысле содержит только статические методы и свойства, не предполагает создание экземпляров), а его нужно "настроить" перед работой, то я делаю статический метод activate(). В принципе, прямо в него можно передать параметром идентификатор языка, который ему загружать (взят ранее из конфига, либо будет замена языка в рантайме), а можно и не делать этого, а жестко прописать обращение в конфиг за языком в самом теле метода activate(). Ну и дальше да, в этом методе загружается нужный .xml - файл и сохраняется в переменную (у меня также создается 4 XMLList'а, так как xml языка содержит 4 "категории" текстов — лейблы на элементах GUI, тексты сообщений для всплывающих окон, тексты инструкций и подсказки (хинты). Но это просто вопрос удобства — я уже как-то писал, что мне нравится "человечность" в коде, когда понятно, что именно запрашивается, а не голое getText(). Ну и вот, создаются статические методы для получения текстов по идентификатору. У меня это выглядело так:
Код AS3:

static public function activate():void
                {
                        if (_activated) return;
                        currentLanguage = FileManager.configXML.language;
                        var languageFile:File = File.applicationDirectory.resolvePath("languages" + File.separator + currentLanguage + ".xml");
                        _currenLanguageXML = FileManager.getXML(languageFile).language[0]; //// FileManager загружает файл языка
                        _labels = _currenLanguageXML.label; //// список ссылок на лейблы
                        _activated = true;
                }
 
static public function getLabel(code:String) : String
{
        return _labels.(@id == code).text();
}

Соответственно в ENG.xml было
Код:

<?xml version="1.0" encoding="utf-8" ?>
<data>
<language id="ENG" native="English">
<!--FileList Context Menu---->
        <label id="0500">Add to Bookmarks</label>
        <label id="0501">Copy the Name</label>
        <label id="0502">Copy the Link</label>
        <label id="0503">Copy the File</label>
        <label id="0504">Rename</label>
        <label id="0505">Delete</label>
        <label id="0506">Add Link</label>
</language>
</data>


Nooob 12.10.2017 23:57

рекомендую значения заворачивать в CDATA

Appleman 13.10.2017 22:00

Цитата:

Сообщение от Wolsh (Сообщение 1202346)
Да проще простого. Поскольку класс "статический" (в смысле содержит только статические методы и свойства, не предполагает создание экземпляров), а его нужно "настроить" перед работой, то я делаю статический метод activate().

Во, я примерно об этом и спрашивал. Выходит, что запустив статический метод activate() в самом начале программы, _currenLanguageXML остаётся "заряженным" нужным списком фраз в течение всего рантайма, верно?

Цитата:

Ну и дальше да, в этом методе загружается нужный .xml - файл и сохраняется в переменную
А можешь показать код загрузки XML от файл-менеджера, если не секрет?

И по коду вопросы:

Код AS3:

if (_activated) return;

Просто защита от дурака или ещё какой-то смысл есть в этом?

Код AS3:

_currenLanguageXML = FileManager.getXML(languageFile).language[0]; //// FileManager загружает файл языка

Не понял в этой конструкции .language[0] на конце...

Wolsh 13.10.2017 23:37

1.
Код AS3:

static public function getText(file:File) : String
                {
                        if (!file.exists) return null;
                        var text:String;
                        _stream.open(file, FileMode.READ); //// _stream это объект класса FileStream
                        _stream.position = 0;
                        text = _stream.readUTFBytes(_stream.bytesAvailable);
                        _stream.close();
                        return text;
                }
 
                static public function getXML(file:File) : XML
                {
                        var xml:XML = null;
                        if (!file.exists) //// в системе нет заданного файла
                        {
                                //// ....выводится попап-окно с ошибкой "файл # не найден"
                                return null;
                        }
                        //// валидация XML
                        try
                        {
                                xml = XML(getText(file)); //// вызывается универсальная загрузка текстового файла getText()
                        }
                        catch (err:TypeError)
                        {
                                //// ....выводится попап-окно с ошибкой "файл # содержит ошибки форматирования"
                        }
                        return xml;
                }

2. Просто защита от дурака.
3. FileManager.getXML(languageFile) возвращает объект XML. Далее идет синтаксис е4х: .language запускает поиск всех узлов language, и возвращает (внимание!) XMLList (в Adobe ж не знают, что узел language у меня один). Но мне нужен не XMLList, а просто один узел language в виде XML-документа. Поэтому из "всего" списка узлов language я беру первый (нулевой). То есть [0] это индекс узла в списке XMLList.

Добавлено через 23 минуты
Предвидя вопрос "а зачем тогда ты вообще делал такую структуру <data><language/></data>" отвечаю : всё просто, в ФАЙЛЕ может содержаться также информация, относящаяся только к файлу, а не к "языку": автор перевода, версия, дата и т.п. Это будут узлы одного уровня с <language/>.

Appleman 14.10.2017 13:25

Wolsh, большое спасибо. Если не возражаешь, возьму за основу в свой проект. У меня почему-то "не стоит" на все эти сервисные функции типа чтения файлов.

Цитата:

Предвидя вопрос "а зачем тогда ты вообще делал такую структуру <data><language/></data>" отвечаю : всё просто, в ФАЙЛЕ может содержаться также информация, относящаяся только к файлу, а не к "языку": автор перевода, версия, дата и т.п. Это будут узлы одного уровня с <language/>.
Всё ясно, ещё одна защита от дурака. Не напасёшься дураков на твои программы. Хоть открывай XML и ещё один <language> туда вставляй! :D

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

Wolsh 14.10.2017 16:37

Потому что AIR позволяет открывать или сохранять файлы синхронно. То есть исполнение дальнейшего кода останавливается и ждет, пока операция выполнится. Поэтому события типа COMPLETE не нужны. Но при желании конечно можно работать асинхронно "по старинке", для этого тоже есть методы (и свои плюшки типа более полного контроля процесса с ловлей ошибок и событий).

Appleman 14.10.2017 19:32

Друзья, пардон, здесь был ещё один нубский вопрос, но я разобрался сам.

caseyryan 14.10.2017 19:53

Цитата:

Соответственно, получаю в консоль "getXML: Ошибка форматирования файла XML!".
Ну а что ты туда можешь ещё получить, если ты сам написал этот текст? Выведи туда лучше err.message или
err.getStackTrace()
От этого будет больше пользы. По крайней мере узнаешь, что на самом деле провоцирует ошибку.

Скорее всего ты что-то не то передаешь в метод getXML(). Что выдает этот трейс? trace (file.nativePath);





п.с.
Код AS3:

_filestream.position = 0; // эта строчка не нужна


Wolsh 14.10.2017 21:19

Код AS3:

_filestream.position = 0; // эта строчка не нужна

..если ты загружаешь одним файлстримом один единственный файл.. так будет точнее.

caseyryan 16.10.2017 06:38

Цитата:

Сообщение от Wolsh (Сообщение 1202400)
Код AS3:

_filestream.position = 0; // эта строчка не нужна

..если ты загружаешь одним файлстримом один единственный файл.. так будет точнее.

Да. Но здесь как раз такой случай.

Партизан 16.10.2017 21:41

Пожалуй опишу свое видение сабжа...
Обычно создаю один файл с несколькими локалями, с примерной структурой типа:
Код:

<string id="" en='' ru=''/>
или вроде того, чтобы id прописывать только раз. Это дает некоторые плюсы: загрузка только одного файла, сложно перепутать id, можно менять интерфейс в рантайме, удобно видеть все версии переводов в одном месте под одним id.
Для удобства я написал пару классов которые отвечают за локализацию:
1. Отвечает за глобальную поддержку локали (хранит переменную текущей локали, при смене генерирует событие смены языка, видим глобально)
2. Транслятор. Отвечает за смену интефейса и отдает нужную строку в зависимости от глобальной локали.
3. Event локали.

Самый важный компонент - это Транслятор, именно через него проходят все строки... Так же он хранит в себе все, что нужно поменять в интерфейсе в данный момент. Реализовано это примерно так: Чтобы вывести строку в textfield, я предварительно регистрирую этот textfield у транслятора и если в рантайме происходит смена языка и этот зарегистрированный textfield находится в списке отображения, его свойство text меняется на текст соответствующей локали. Впрочем, вместо texfield может быть любой объект DisplayObject с любым именем свойства. Так же можно запросить строку определенного id с нужной локалью.
Собственно такая система решила большинство проблем с локализацией.

ZackMercury 16.10.2017 22:43

Цитата:

Это дает некоторые плюсы:
Цитата:

загрузка только одного файла,
Загрузка только одного файла с одним языком чем-то отличается? А, ну да, он меньше весит, а надо же напихать туда сразу все сто языков.
PHP код:

сложно перепутать id 

А как его можно перепутать, разделив языки на файлы?
Цитата:

можно менять интерфейс в рантайме
Можно менять интерфейс в рантайме, подгрузив другой язык и отправив событие изменения языка.
ИМХО, при добавлении новых языков ваш код станет нечитаем. Ладно когда языка всего 2, но в наше время этого мало.
Вообще не понимаю, зачем так делать.
Один раз написал XML для русского, потом Сохранить как, и перевёл на инглиш, потом сохранить как, и перевёл на немецкий. Удобно, красиво.

Партизан 17.10.2017 00:49

Цитата:

Сообщение от ZackMercury (Сообщение 1202434)
Загрузка только одного файла с одним языком чем-то отличается? А, ну да, он меньше весит, а надо же напихать туда сразу все сто языков.
PHP код:

сложно перепутать id 

А как его можно перепутать, разделив языки на файлы?

Чтобы "налету" сменить язык, он должен быть уже подгружен, это означает, что вам придется грузить сразу все локали или грузить нужную после смены языка пользователем, а это время. В зависимости от скорости доступа к файлу (тут нужно учесть откуда этот файл грузится, локально или удаленно и конечно скорость доступа к данным), нужно соблюсти баланс между обновлением интерфейса и условиями ТЗ заказчика. На моем опыте было не более трех-четырех языков в приложении. Конечно это не относится к сервисам worldwide типа. Я описал типичный расклад. В случае XML который я указал как пример, тут спорно по объему данных в случае локалей. Структура одного файла может быть компактней 20-ти и наоборот.

Перепутать id даже в трех файлах довольно легко... Переводчик мог просто запариться и перепутать id (он же гуманитарий скорее всего :) ) и вместо "Привет" на другом языке у вас может быть, к примеру, "Exit"
Код:

RU_file:
<ru>
    <id="01" str="Привет"/>
</ru>

EN_file:
<en>
    <id="O1" str="Exit"/>
</en>

Цитата:

ИМХО, при добавлении новых языков ваш код станет нечитаем. Ладно когда языка всего 2, но в наше время этого мало.
Я привел упрощенный вид XML просто для понимания(хотя и в таком виде использую если точно знаю, что это конечный продукт который дальше меня не пойдет и развития не получит). Структура может быть изменена не нарушая концепции одного id. Благо у XML есть куча возможностей для этого, и все будет читаемо. Намеренно, конечно же, можно любой текст превратить в нечитаемый.
Цитата:

Вообще не понимаю, зачем так делать.
"Ты явно не бывал в Сингапуре..." (с) Pirates of the Caribbean :)

caseyryan 17.10.2017 11:39

Цитата:

Чтобы "налету" сменить язык, он должен быть уже подгружен
Не должен. Его можно так же "на лету" подгрузить. Собственно, обычно так и делают. Да и зачем может потребоваться смена языка на лету? Единственное, где я вижу в этом какой-то смысл - это языковое приложение типа разговорника или словаря.
А в теме, очевидно, речь идет об игре, для которой язык можно сразу установить равным языку устройства.
Цитата:

Переводчик мог просто запариться и перепутать id (он же гуманитарий скорее всего ) и
Для этого существуют тесты. Ошибки возможны всегда. И лучше не использовать такие непонятные ID, а использовать человекочитаемые строки, вместо них. Типа
Код AS3:

RU_file:
<ru>
    <id="greeting" str="Привет"/>
    <id="exit" str="Выход"/>
</ru>
 
EN_file:
<en>
    <id="greeting" str="Hi"/>
    <id="exit" str="Exit"/>
</en>

Вероятность ошибки человека в таком случае, сводится к минимуму. Да и дебажить такой код зрительно будет гораздо проще.

п.с. Я тоже переводчик по образованию, но это не мешает мне быть программистом ;)

Партизан 17.10.2017 12:59

Код:

Не должен. Его можно так же "на лету" подгрузить. Собственно, обычно так и делают.
Так делают, когда не важно время обновления интерфейса.
Цитата:

Да и зачем может потребоваться смена языка на лету? Единственное, где я вижу в этом какой-то смысл - это языковое приложение типа разговорника или словаря.
На вскидку - навигаторы ТЦ, информационные киоски, анкетные, рекламные приложения...
Цитата:

А в теме, очевидно, речь идет об игре, для которой язык можно сразу установить равным языку устройства.
Я лишь описал реализацию которая может быть полезна как по теме, так и в последующих проектах.
Цитата:

Для этого существуют тесты. Ошибки возможны всегда.
Зачем тогда собственноручно повышать вероятность этих ошибок? Допустим, есть 100 строк, и три языка. Это 100 id в трех файлах... Заметить ошибку перевода будет достаточно сложно, даже если просто перепутать id фразы, она с высокой вероятностью пройдет в продакшн. Куда проще сравнить три-четыре перевода под одним id
Код:

<string id="hello">
    <ru>Привет</ru>
    <en>Hi</en>
    <kz>Cәлем</kz>
    <by>Да пабачэння</by>
</string>

В таком случае ошибку заметить гораздо легче еще на этапе переводов, причем зачастую ее может заметить человек даже не владеющий языком. Это опять же ИМХО и возможно не универсально для абсолютно всех проектов, но мы же тут как раз и собираемся для обсуждения, а реализация остается на усмотрение каждого.

caseyryan 17.10.2017 14:16

Цитата:

На вскидку - навигаторы ТЦ, информационные киоски, анкетные, рекламные приложения...
Навигаторы ТЦ и инфо киоски - это не персональное устройство, тут вообще другая сфера применения. Рекламные приложения вполне могут сразу адаптироваться к языку ОС или браузера, так же как и анкетные.
Цитата:

Куда проще сравнить три-четыре перевода под одним id
Что мешает открыть два блокнота / ide с одним и тем же текстом рядом, и точно так же сравнить?
Проверять вот таким образом даже 100 строк в трех языках, тоже совсем не камильфо. Если уж на то пошло, то гораздо лучшим вариантом будет сделать небольшую утилитку, которая будет брать по порядку ID и для каждого языка выводить все переводы на экран рядом, без лишних тегов. Но хранить все переводы в одном файле - плохо, особенно для мобильников. Подгрузка нового файла с переводом, с локального диска, даже на слабом устройстве займет несколько милисекунд. Для человека это будет мгновенно + лишнюю память жрать не будет.

ZackMercury 17.10.2017 19:07

PHP код:

Чтобы "налету" сменить языкон должен быть уже подгруженэто означаетчто вам придется грузить сразу все локали или грузить нужную после смены языка пользователема это время

Смена языка - это единоразовое действие, скорость обновления интерфейса при котором совершенно не должна быть важна.
К тому же, это загрузка текстового файла, она выполняется за доли секунды даже со слабейшим интернетом(может занять дольше, только если это мобильный инет)
Тут скорее надо переживать за скорость доставания данных из XML документа, которая при включении всех языков в один документ будет ниже.


Часовой пояс GMT +4, время: 11:56.

Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2026, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.