Как проще и эффективнее организуется локализация проекта? Ситуация такая: Есть проект (в смысле программа) на VC++, он состоит из множества компонент, которые могут добавляться/убирать в виде плагинов. Все текстовые сообщения находятся в ресурсных библиотеках (их много, у каждого плагина — своя). Нужно без перекомпиляции иметь возможность переводить тексты на разные языки, причем так, чтоб можно было просто поддерживать несколько языков. Основные требования:
1. Локализация без перекомпиляции
2. Модифицикация библиотеки с ресурсами должна быть ПРОЗРАЧНА для всех остальных библиотек (т.е.они должны продолжать работать как бы со стандартными ресурсами)
Мне видится идеальным такое решение — все текстовые сообщения хранятся в текстовом файле и есть утилита которая позволяет осуществить подмену одного текста на другой... Возможно ли такое? Попадались ли примеры? Есть ли другие варианты?
Я б применил паттерн "Strategy", на C# это выглядит так.
// это в одном модуле
interface IText
{
string GetText(int id);
}
// Пусть это будет в russian.dll
class Text : IText
{
public string GetText(int id)
{
if (id == 1) return "Сообщение"; // главное вернуть строку, а как — это вопрос реализации ;)
}
}
// Пусть это будет в english.dll
class Text : IText
{
public string GetText(int id)
{
if (id == 1) return "Message";
}
}
// Пусть это будет ещё где-нибудь
class B
{
private IText text;
public B(IText _text)
{
text = _text;
}
public void DoSomething()
{
MessageBox.Show(text.GetText(1));
}
}
class MainClass
{
public void MainProc()
{
Assembly a = Assembly.LoadFrom("Russian.dll"); // путь можно считать откуда-нибудь, из реестра например
IText text = (IText)Activator.CreateInstance(a.GetType("Text"));
B b = new B(text);
b.DoSomething();
}
}
Теперь, если надо поменять язык — "Russian.dll" меняем на "English.dll" при загрузке assembly. Всё очень просто, не так ли? ;)
Здравствуйте Mishka, Вы писали:
M>Я б применил паттерн "Strategy", на C# это выглядит так.
M>...
M>Теперь, если надо поменять язык — "Russian.dll" меняем на "English.dll" при загрузке assembly. Всё очень просто, не так ли? ;)
Мда, я бы так не сказал.
В свое время мне приходилось заниматься проблемой локализации большого проекта
состоящего из множества DLL (COM серверов и DLL Extension)
Способ был придуман не самый простой (но мы же не ищем легких путей :) и возможно
не самый лучший.
Общая идея такова:
Основной язык (например английский) хранится в ресурсах самого модуля.
Для каждого дополнительного языка создается отдельная DLL (без кода, тольо ресурсы).
При старте программы решаем какой язык нужен и грузим DLL
HMODULE hResMod = ::LoadLibrary("<resource DLL name>"); // можно даже ::LoadLibraryEx но там есть нюансыif(hResMod) AfxSetResourceHandle(hResMod);
P.S. А вариант с текстовым файлом это конечно, первое что приходит на ум, НО
порой при переводе текст не умещается например на кнопке дилога, значит требуется
изменить размер кнопки, или например текст на картинке иногда тоже нужно перевести,
а в текстовый файл BITMAP не засунешь. Локализация это не только перевод строк,
это еще и корректировка внешнего вида приложения.
Здравствуйте Willi, Вы писали:
W>P.S. А вариант с текстовым файлом это конечно, первое что приходит на ум, НО W>порой при переводе текст не умещается например на кнопке дилога, значит требуется W>изменить размер кнопки, или например текст на картинке иногда тоже нужно перевести, W>а в текстовый файл BITMAP не засунешь. Локализация это не только перевод строк, W>это еще и корректировка внешнего вида приложения.
В один прекрасный день решили они перенести приложение из Windows в Web (.NET, Linux, MacOS,...), глядят а все ресурсы в dll, да ещё и в разных :(
и что ж они решили делать тогда? Правильно, переписать всё заново и перерисовать все формы.
Грустно... а ведь могли использовать XML и Design patterns. Но голова многим даётся только чтоб они в неё ели...
Здравствуйте Mishka, Вы писали:
M>В один прекрасный день решили они перенести приложение из Windows в Web (.NET, Linux, MacOS,...), глядят а все ресурсы в dll, да ещё и в разных :( M>и что ж они решили делать тогда? Правильно, переписать всё заново и перерисовать все формы. M>Грустно... а ведь могли использовать XML и Design patterns. Но голова многим даётся только чтоб они в неё ели...
Здравствуйте Willi, Вы писали:
W>Здравствуйте Mishka, Вы писали:
M>>В один прекрасный день решили они перенести приложение из Windows в Web (.NET, Linux, MacOS,...), глядят а все ресурсы в dll, да ещё и в разных :( M>>и что ж они решили делать тогда? Правильно, переписать всё заново и перерисовать все формы. M>>Грустно... а ведь могли использовать XML и Design patterns. Но голова многим даётся только чтоб они в неё ели...
W>Папа, а скем ты сейчас разговаривал?
Здравствуйте Willi, Вы писали:
W>Здравствуйте Mishka, Вы писали:
M>>Сынок, мыслил вслух...
W>:) W>Ну тадыть просветите, шо конкретно вы имели ввиду? W>А то вы чезчур витьевато выражаетесь. W>Ну не догнал я. (наверное надо пойти поесть:)
Есть такая мысль, что когда пишется большой проект, то сначала он проектируется, причём архитекторы пытаются предугадать возможные дальнейшие изменения. Потому набирается огромное количество абстрактных классов, чей реализацией занимаются прикладные программисты.
Пример: если предположить что ресурсы надо хранить и загружать, то надо придумать два нечто: где хранить и как загружать. Первое должно быть переносимо (XML тут может пригодиться), второе — это чистый паттерн "Strategy": абстрактный класс LoadResource с методом Load, и его реализации — class LoadFromDLL, LoadFromSOAP, LoadFromOracleDB, и пр. Основное приложение подгружает ресурсы либо в начале работы: LoadResource->Load(), либо по мере надобности: LoadResource->Load(RESOURCE_ID).
Преимущества очевидны.
Здравствуйте Mishka, Вы писали:
M>Здравствуйте Willi, Вы писали:
W>>Здравствуйте Mishka, Вы писали:
M>>>Сынок, мыслил вслух...
W>>:) W>>Ну тадыть просветите, шо конкретно вы имели ввиду? W>>А то вы чезчур витьевато выражаетесь. W>>Ну не догнал я. (наверное надо пойти поесть:)
M>Есть такая мысль, что когда пишется большой проект, то сначала он проектируется, причём архитекторы пытаются предугадать возможные дальнейшие изменения. Потому набирается огромное количество абстрактных классов, чей реализацией занимаются прикладные программисты. M>Пример: если предположить что ресурсы надо хранить и загружать, то надо придумать два нечто: где хранить и как загружать. Первое должно быть переносимо (XML тут может пригодиться), второе — это чистый паттерн "Strategy": абстрактный класс LoadResource с методом Load, и его реализации — class LoadFromDLL, LoadFromSOAP, LoadFromOracleDB, и пр. Основное приложение подгружает ресурсы либо в начале работы: LoadResource->Load(), либо по мере надобности: LoadResource->Load(RESOURCE_ID). M>Преимущества очевидны.
Да, звучит заманчиво.
Но блин работы...
Но если денег и времени много, то почему бы и нет.
И... Закончин ли тобой хоть один проект перевода софтины на другой язык, сделанный по этой замечательной схеме?
Не обижайся, но это все рекламма, а жизнь она из работы соотоит. И в VC вся эта работа уже сделана. А если на Веб чё надо перенести, то проще бизнес логику в COM-объекты (или какие другие) вынести. Ведь все равно код десктоп-гуи в к Вэбу не прикрутишь. :(
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте Mishka, Вы писали:
M>... чей реализацией занимаются прикладные программисты.
Тупые кодеры значить...
А я тут мысль одну читывал... мол 99% программирования это проектирование, а конструирование — это компиляци и линковка.
Во как!
Исходя из этой мысли те кого ты конструкторами называешь должны не классы определять, а только фича-лист составлять. А проектирование и реализация фичь должны делаться разработчиками, а не кодерами. Хотя к основному вопросу ...
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте VladD2, Вы писали:
VD>Здравствуйте Mishka, Вы писали:
VD>Да! Действительно заманчиво.
VD>Возникает только два вопроса:
VD>Mishka! Чего ты начиталься?
VD>И... Закончин ли тобой хоть один проект перевода софтины на другой язык, сделанный по этой замечательной схеме?
VD>Не обижайся, но это все рекламма, а жизнь она из работы соотоит. И в VC вся эта работа уже сделана. А если на Веб чё надо перенести, то проще бизнес логику в COM-объекты (или какие другие) вынести. Ведь все равно код десктоп-гуи в к Вэбу не прикрутишь. :(
Начитался я всякой чуши (analysis, design patterns), а потом решил сделать что-то реальное. Теория и практика всегда различались. Сейчас имею рабочий прототип софтины, сделаной по этой схеме (жду релиза VS.NET для завершения проекта). Там кроме всего прочего предусмотрена возможность переноса приложения в Web с минимальными переписываниями, а десктоп-гуи — это лишь реализация одного из наборов абстрактных классов, которой (реализацией) как раз и должны заниматься программисты, и не думаю я, что эта задача для кодеров, не справяться они. Для кодеров специально всё и делается, чтоб писали они бизнес-логику и не лезли своими длинными носами в управление UI и DB. Тупые программеры в Ирландии, что с ними сделать :((.
А рекламой я не занимаюсь, просто кажется мне, что подходы у нас разные: одни решают задачу технически (локально), другие теоретически (глобально), но главное всегда, чтоб был результат, который кто-то оплачивал ;)