Наш проект, о котором я писал в блоге на РСДН,
и о котором можно прочитать в блоге на нашем сайте sem-tech.net,
пока представляет собой стартапный экспериментальный образец.
Чтобы сделать его программным продуктом, еще нужно много работы.
Semantic IDE написан в Студии на C# с использованием WPF и некоторых бесплатных компонентов.
И в данный момент встал вопрос о реализации механизма локализации и соответственно механизма настроек.
Что требует локализации:
— интерфейс среды (русско-английский)
— сообщения (русско-английский)
Отдельно еще два связанных множества:
— лексические элементы языка (ключевые слова)
— синтаксическое представление программы (грамматика представления в форме БНФ)
Здесь не просто русско-английский.
В данном случае нужно спроектировать механизм добавления нового синтаксиса и соответственно к нему — новый словарь лексики.
Первоначально об этом особо не думали, поскольку сначала хотели убедиться в жизнеспособности идеи.
В результате сообщения равномерно разбросаны по всему коду, причем в явном виде — строковые литералы.
Теперь встала такая проблема:
Допустим, в Solution добавляется новый Project.
В нем, естественно, есть масса сообщений.
И требуется увязать эти новые сообщения с уже существующим механизмом локализации.
Возникает некое противоречие:
— с одной стороны хотелось бы иметь некоторый централизованный механизм добавления-изменения-удаления настроек
— с другой стороны возникает естественное желание в конкретном проекте иметь все, что к этому проекту относится.
Создавать некий базовый набор классов, а все проекты в части локализации от него наследуют (или композируют) ?
Поделитесь опытом.
В перспективе предстоит перенос в линукс, поэтому не хотелось бы использовать для локализации виндо-микрософтовские механизмы.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, Ziaw, Вы писали:
Z>Здравствуйте, LaptevVV, Вы писали:
LVV>>Создавать некий базовый набор классов, а все проекты в части локализации от него наследуют (или композируют) ? Z>На чем пишете? Механизмы локализации и хранения настроек есть готовые для всех платформ, надо просто выбрать. Z>Если хотите писать сами — просто посмотрите то, что уже есть. В любом случае базовый набор классов — антипаттерн для данных задач.
Спасибо.
Пока пишем на C# в Студии с использованием WPF.
Но поскольку проект развивается — нужно как-то обеспечить подключение новых настроек к уже имеющимся.
Причем с наименьшими затратами для программиста, который подключает новый проект в Solution.
Способ хранения: либо как проект нашей среды, либо в некоей БД.
Последнее мне нравится меньше — лишняя сущность в среде появляется.
B пока как-то пазл не складывается в ясную картину.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, LaptevVV, Вы писали:
LVV>Но поскольку проект развивается — нужно как-то обеспечить подключение новых настроек к уже имеющимся.
Так, а тут нет никакой путаницы в терминологии?
В проектах дотнета настройки и локализация никак друг с другом не связаны, зачем для локализации "подключать настройки"?
Первое — это значения, которые нужно вытащить из кода, чтобы при их изменении не пришлось код перекомпилировать.
Второе — значения, которые нужно вытащить из кода, чтобы подменять при смене локали пользователя.
В большинстве случаев для первого хватает стандартного механизма настроек (он расширяем — можно подменить способ хранения / загрузки настроек).
Для второго — дотнетовских ресурсов и ресурсных сборок.
Плюс, не совсем понятно, куда нужно добавить поддержку локализации — в саму IDE, или ешё и в проекты?
Здравствуйте, Sinix, Вы писали:
S>Здравствуйте, LaptevVV, Вы писали:
LVV>>Но поскольку проект развивается — нужно как-то обеспечить подключение новых настроек к уже имеющимся. S>Так, а тут нет никакой путаницы в терминологии? S>В проектах дотнета настройки и локализация никак друг с другом не связаны, зачем для локализации "подключать настройки"? S>Первое — это значения, которые нужно вытащить из кода, чтобы при их изменении не пришлось код перекомпилировать. S>Второе — значения, которые нужно вытащить из кода, чтобы подменять при смене локали пользователя. S>В большинстве случаев для первого хватает стандартного механизма настроек (он расширяем — можно подменить способ хранения / загрузки настроек). S>Для второго — дотнетовских ресурсов и ресурсных сборок. S>Плюс, не совсем понятно, куда нужно добавить поддержку локализации — в саму IDE, или ешё и в проекты?
Скорее всего, у нас не совсем настройки в традиционном понимании этого термина.
Первое, что хотелось бы прояснить для себя.
Поскольку проект развивается, то интерфейс будет еще достраиваться.
Для каждого текстового элемента интерфейса надо иметь два языка. Это настройки или локализация?
Не хотелось бы при каждом изменении-добавлении лезть в код и перетранслировать весь проект.
Второе. В нашей среде лексика и синтаксис — сменные. Кроме того, мы можем добавлять новый синтаксис-лексику.
Естественно, новый синтаксис должен появиться в списке сменяемых языков (это элемент интерфейса).
Третье. Развитие проекта потребует включение в Solution новых проектов.
В каждом проекте неизбежно будут некоторые сообщения пользователю.
С одной стороны эти сообщения должны быть двуязычными.
С другой стороны, хотелось бы в рамках Solution иметь некий общий механизм (отдельный проект ?),
позволяющий минимизировать усилия по локализации этих сообщений.
Внешнее представление всех этих вещей не очень меня интересует, поскольку тут можно хранить сотней способов.
А вот внутри...
Как я понимаю, проще всего создать объект-настройщик, в котором все настройки прописаны как множество свойств. Можно определить набор enumов, которые будут индексировать контейнер.
В моем случае будет не один объект-настройщик. а два. или скорее, три.
И в каждом собственный набор свойств.
Собственно, пока пазл именно с сообщениями не складывается.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, LaptevVV, Вы писали:
LVV>Пока пишем на C# в Студии с использованием WPF.
О какой кроссплатформенности может идти речь тогда? WPF это Winows прибитые гвоздями.
LVV>Но поскольку проект развивается — нужно как-то обеспечить подключение новых настроек к уже имеющимся. LVV>Причем с наименьшими затратами для программиста, который подключает новый проект в Solution. LVV>Способ хранения: либо как проект нашей среды, либо в некоей БД. LVV>Последнее мне нравится меньше — лишняя сущность в среде появляется. LVV>B пока как-то пазл не складывается в ясную картину.
Попробуйте описать картину более полно. Потому, что это, похоже, не является ни настройками ни локализацией, а выглядит как узкая задача, которая требует своего решения.
Здравствуйте, Ziaw, Вы писали:
LVV>>B пока как-то пазл не складывается в ясную картину.
Z>Попробуйте описать картину более полно. Потому, что это, похоже, не является ни настройками ни локализацией, а выглядит как узкая задача, которая требует своего решения.
Собственно, постепенно остается только вопрос с сообщениями.
Еще раз (и для себя тоже) повторю.
Развитие проекта потребует включение в Solution новых проектов.
В каждом проекте неизбежно будут некоторые сообщения пользователю.
В текущей версии, которая писалась как пробный исследовательский проект, никто не задумывался о сообщениях пользователю.
В результате сообщения разбросаны по всему коду, причем в явном виде — строковый литерал.
Теперь встала проблема:
1. Все текущие сообщения собрать в одном месте и создать механизм переключения русский-английский
2. Новые сообщения должны быть без проблем включены в этот механизм.
Пока мыслю так:
— выбрать внешнее представление сообщений (например, простой txt) — тут очень много вариантов, вплоть до хранения всего в БД.
Вот, например, здесь можно посмотреть: http://www.javaportal.ru/java/articles/appsettingsdemo.html
— при запуске среды сообщения читаются с внешнего представления в некий контейнер
— все места в коде, где есть вывод сообщения, заменяются на вывод элемента контейнера.
Контейнер может быть полем некоего класса настроек, например.
Пока новых сообщений нет — все хорошо. Локализация русский-английский тоже решается в рамках этих мыслей.
Проект дальше развивается и еще будут дописываться некоторые механизмы.
Предположим, программер (причем, новичок, который не знает всего объема и тонкостей общего Solution — да ему и не нужно)
пишет новый проект и включает его в общий Solution.
В его проекте есть сообщения пользователю.
Хотелось бы в рамках общего Solution дать ему механизм, который без проблем позволил бы ему новые сообщения выдавать,
и не требовал бы переделки кода уже сделанного.
Ну, допустим, он свои сообщения без проблем впишет во нешнее представление.
Хотя все зависит от способа хранения — возможно, придется писать отдельный интерфейс для этого.
При запуске программы тоже без проблем все сообщения добавятся в контейнер.
Но далее ...
При написании своего кода он должен обращаться к элементам контейнера сообщений — причем, новым элементам.
Хотелось бы, чтобы программер имел дело только со своими сообщениями, и не лез в общий механизм.
Или создать класс, от которого в новом проекте создается наследник, и добавляются просто новые поля?
Плюс переопределяются методы, чтобы иметь дело только с новыми полями-сообщениями ?
То есть, хотелось бы в рамках Solution иметь некий общий механизм (отдельный проект ?),
позволяющий минимизировать усилия по локализации этих сообщений.
Причем, естественно, в рамках принципа SOLID: код закрыт для изменений и открыт для расширений.
Пока кроме наследования не вижу как это сделать.
Собственно, пока пазл именно с новыми сообщениями не складывается.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Ваши идеи очень интересны, в ближайшее время собираюсь пощупать вашу IDE.
Без особой конкретики, хочу высказать два пожелания:
1. Отходите от концепции двух языков "русский-английский". Чем остальные хуже? Проектируйте в расчете на любой (ну хотя бы из европейских).
2. Если планируете кроссплатформенность, постарайтесь сделать это как можно раньше. Потом объем работы может оказаться неподъемным.
И посмотрите на линуксовые механизмы и инструменты локализации. Они вполне кроссплатформенны.
Здравствуйте, wildwind, Вы писали:
W>Ваши идеи очень интересны, в ближайшее время собираюсь пощупать вашу IDE.
Спасибо. W>Без особой конкретики, хочу высказать два пожелания: W>1. Отходите от концепции двух языков "русский-английский". Чем остальные хуже? Проектируйте в расчете на любой (ну хотя бы из европейских).
Ну, там, где два — там и все остальные... W>2. Если планируете кроссплатформенность, постарайтесь сделать это как можно раньше. Потом объем работы может оказаться неподъемным. W>И посмотрите на линуксовые механизмы и инструменты локализации. Они вполне кроссплатформенны.
Это да. Я начал думать об этом год назад.
Но программист в то время был один, да и не все было реализовано, что было по минимуму необходимо.
Теперь минимум реализован, и я настаиваю, что дальнейшие работы должны вестись с учетом локализации.
Но как вы понимаете, у студентов всегда находится время на переделку, но никогда нет времени на проектирование...
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, LaptevVV, Вы писали:
LVV>Развитие проекта потребует включение в Solution новых проектов.
И сразу вопрос. А какой частью итогового приложения будет являться этот Solution? Все собирается в один большой и страшный исполняемый файл? И куда тогда идут все дополнительные файлики? Или каждый solution собирается в библиотеку (dll) или ее часть (в одной dll может быть несколько библиотек)? Кто тогда гарантирует нужный LIBRARY_PATH во время выполнения библиотеки? Разнесены ли зависимости между solutions и deployment unit (те же dll)? Т.е. solutions должны зависеть только от зависимостей, а зависимости между dll строятся по зависимостям между solution.
Как связаны жизненные циклы компонентов, предоставляемых solution? Т.е. откуда они получают другие зависимости (правильно сконфигурированные сервисы)? Или все зависимости чисто кодом и каждый компонент предоставляет только набор функций (это вряд ли, у вас какие-то настройки вроде есть).
В зависимости от ответов на эти вопросы могут быть различные решения. Например, в момент создания компонента можно передавать ему название локали, в которой этот компонент будет работать. Все остальное — его проблемы (правда, он должен знать хотя бы, где брать правильные файлики). Или в вызовы передавать требуемую локаль. Последний вариант для веб-сервера может быть одним из немногих доступных для него решений.
LVV>1. Все текущие сообщения собрать в одном месте и создать механизм переключения русский-английский
Пока рекомендую требовать при смене языка перезапуск приложения. Не придется охотится за утечками памяти (лишние подписки на смену языка) и потерянными подписками на такую смену (т.е. что-то может не поменяться).
LVV>2. Новые сообщения должны быть без проблем включены в этот механизм.
Надеюсь, все помнят, что конкатенацией строк сообщения не формируются (за исключением очень специальных случаев)? Причина простая — в разных языках порядок слов в предложениях может быть разный. В простешем случае вся локализация идет через String.format.
LVV>Пока мыслю так: LVV>- выбрать внешнее представление сообщений (например, простой txt) — тут очень много вариантов, вплоть до хранения всего в БД.
Сразу замечу, что "внутреннее представление" в исходной программе и итоговой может отличаться. Проще всего править сообщения в простом текстовом файле.
LVV>Контейнер может быть полем некоего класса настроек, например.
В настройки не советую. Все-таки назначение совершенно другое, техники используются другие.
И еще одна замечательная причина. Локализация в общем случае — не только набор сообщений. Локализовываться могут некоторые картинки, например. А может быть и код, специфичный для локалей. Например, форматирование даты/времени/чисел (для этого обычно в платформе есть инструменты с форматными строками). Или выводить числительные прописью/согласовывать падежи ("в программе найдена 1 ошибка", "в программе найдено 2 ошибки", подобное через стандартные инструменты не всегда делается). Так что передавать локализации через "стандартный контейнер" может быть не очень хорошей идеей.
LVV>Но далее ... LVV>При написании своего кода он должен обращаться к элементам контейнера сообщений — причем, новым элементам. LVV>Хотелось бы, чтобы программер имел дело только со своими сообщениями, и не лез в общий механизм.
Смотрите жизненный цикл компонента. Там ему можно передать только его настройки. Как именно, зависит от того, какой способ настройки прилжоения вы избрали.
LVV>Или создать класс, от которого в новом проекте создается наследник, и добавляются просто новые поля?
А что именно будет от родителя наследовано? Простейший класс реализации выглядит так: MessageBundle.format(key : String, ...args: Object). Ну и конструктор для создания его по локали. А если делать поля (статическая проверка), зачем тогда наследоваться? Стоит просто иметь ссылку на нужные зависимости. LVV>Плюс переопределяются методы, чтобы иметь дело только с новыми полями-сообщениями ?
Пока вижу всего один метод. Который не нужно переопределять (нужная конфигурация идет через конструктор).
LVV>То есть, хотелось бы в рамках Solution иметь некий общий механизм (отдельный проект ?), LVV>позволяющий минимизировать усилия по локализации этих сообщений.
Не просто в рамках Solution, а в рамках всей системы сборки. Зависимости от общей библиотеки тоже могут быть.
LVV>Пока кроме наследования не вижу как это сделать.
Вот не вижу все еще наследования. Не вижу, что можно было бы унаследовать.
LVV>Собственно, пока пазл именно с новыми сообщениями не складывается.
Есть несколько вариантов.
Варианты связывания:
1. Я приводил выше — передавать название локали в нужные места. Каждый solution сам разбирается, как и что локализовывать. В качестве нижележащего механизма можно взять какие-нибудь платформенные message/resource bundle.
2. Получать подобные bundle извне. В этом случае прилжоение инстанциирует нужную локаль и передает ее в нужные места (в явном виде, либо при "старте" компонента, либо в методы). Можно передавать и инстанциированные классы локализатора (которые числительные/падежи форматируют, например). С точки зрения работы программы, локализация — обыкновенный компонент (только конкретная реализация выбирается чуть сложнее, чем для самого кода библиотеки).
3. Сделать статическую точку доступа (свой класс сообщений для solution) и разруливать доступ к нему с использованием механизмов вроде LIBRARY_PATH (на java это будет classpath с подключением jar только от нужной локали).
Варианты реализации bundle:
1. Можно использовать что-нибудь стандартное слаботипизированное. В java — resource bundle (или message bundle) и простенькие обертки над ними. Контроля над типами аргументов в коде не будет.
2. Генерировать строго типизированные форматтеры/провайдеры по описаниям. По тем же "простым текстовым файлам" генерируется строго типизированный класс (классы для всех локалей). Возможно, еще и общий интерфейс. Формат слишком сложный не нужно — форматирование строк (какие-нибудь precision и т.п.). Возможно — ссылки на локализации из базовых модулей (стандартные названия, надписи). Может быть, вызов функций из библиотеки поддержки (числительные прописью). Циклов/итераций/условий вроде бы не нужно.
Варианты связывания и реализации bundle ортогональны друг другу.
Я использовал разные способы. На actionscript была кодогенерация и статическая точка доступа (генерировалось несколько одинаковых классов с разным содержанием и в код подгружались в разном виде). На javascript было что-то слаботипизированное (потому что javascript) и зависимость в виде экземпляров модулей (п. 2 из связывания, так устроена модульность в js).