Когда компилил Rotor меня порозило то, что для компиляции надо поставить Perl.
Оказывается в Framework Microsoft решает эту проблему следующим образом.
Есть файл resource.txt со строками
...
Arg_IndexOutOfRangeException = Index was outside the bounds of the array.
Arg_NotSupportedException = Specified method is not supported.
...
На основе этого файла при помощи perl script генерится класс
//------------------------------------------------------------------------------
// This file is autogenerated by gensr.pl utilitity. Do not modify.
//------------------------------------------------------------------------------namespace MyNameSpace {
using System;
using System.Reflection;
using System.Globalization;
using System.Resources;
using System.Text;
using System.Threading;
using System.ComponentModel;
/// <summary>
/// AutoGenerated resource class. Usage:
///
/// string s = StrR.GetString(StrR.m_MyIdenfitier);
/// OR
/// string s = StrR.MyIdenfitier;
///
/// </summary>internal sealed class SR {
static SR loader = null;
static CultureInfo info = Thread.CurrentThread.CurrentCulture;
ResourceManager resources;
...
internal const string Arg_IndexOutOfRangeException = "Arg_IndexOutOfRangeException";
internal const string Arg_NotSupportedException = "Arg_NotSupportedException";
...
private SR() {
Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;
resources = new System.Resources.ResourceManager("MyNameSpace.resource", this.GetType().Module.Assembly);
}
private static SR GetLoader() {
if (loader == null) {
lock(typeof(SR)) {
if (loader == null) {
loader = new SR();
}
}
}
return loader;
}
public static string GetString(string name, params object[] args) {
// null CultureInfo: let ResouceManager determine the culturereturn GetString(info, name, args);
}
public static string GetString(CultureInfo culture, string name, params object[] args) {
SR sys = GetLoader();
if (sys == null)
return null;
string res = sys.resources.GetString(name, culture);
if (args != null && args.Length > 0) {
return String.Format(res, args);
}
else {
return res;
}
}
public static string GetString(string name) {
return GetString(info, name);
}
public static string GetString(CultureInfo culture, string name) {
SR sys = GetLoader();
if (sys == null)
return null;
return sys.resources.GetString(name, culture);
}
public static bool GetBoolean(string name) {
return GetBoolean(name);
}
public static bool GetBoolean(CultureInfo culture, string name) {
bool val = false;
SR sys = GetLoader();
if (sys != null) {
object res = sys.resources.GetObject(name, culture);
if (res is bool) {
val = (bool)res;
}
}
return val;
}
.....
}
}
Я конечно же не стал изобретать велосипед, немного подточил gensr.pl что бы генерил более удобный для использования класс SR, но все же не покидует душу вопрос — Неужели нет другого механизма или способа для локализации кода????
VP>Я конечно же не стал изобретать велосипед, немного подточил gensr.pl что бы генерил более удобный для использования класс SR, но все же не покидует душу вопрос — Неужели нет другого механизма или способа для локализации кода????
в принципе этот — самый нормальный
но можно и извратиться :)
создать локализованную форму с кучей лейблов и юзать ее:
Здравствуйте, V.Petrovski, Вы писали:
VP>По поводу визуальной части вроде все ясно VP>1. Ставишь свойство Localizable в true VP>2. Выбираешь нужный Language и локализуешь
VP>А вот как по поводу таких вещей
VP> MessageBox.Show("Unknown error "+ex.Message);
Посмотри на класс ResourceManager. Подробности можешь углядеть в исходниках януса.
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, V.Petrovski, Вы писали:
VP>>По поводу визуальной части вроде все ясно VP>>1. Ставишь свойство Localizable в true VP>>2. Выбираешь нужный Language и локализуешь
VP>>А вот как по поводу таких вещей
VP>> MessageBox.Show("Unknown error "+ex.Message);
AVK>Посмотри на класс ResourceManager. Подробности можешь углядеть в исходниках януса.
//------------------------------------------------------------------------------
// This file is autogenerated by gensr.pl utilitity. Do not modify.
//------------------------------------------------------------------------------
...
internal sealed class SR {
static SR loader = null;
static CultureInfo info = Thread.CurrentThread.CurrentCulture;
ResourceManager resources;
...
В конечном итоге все managed ресурсы получаются через класс ResourceManager,
я про то, как проще создать продукт поддерживающий локализацию. Если использовать только голый ResourceManager возникают проблемы (неудобства):
1. Где его создать и когда??? (ну это не очень мощная проблема, но новичка загоняет)
2. Где хранить ключи для получения ресурсов??? (GetString(key))
3. Как быть когда ключы изменяются, добавляются и удаляются??? (менять константы в коде — copy+paste)
4. Как сдержать нервы после первых трех пунктов?? (это все рутина которую разработчик пытается устранить написав генерилку)
Здравствуйте, V.Petrovski, Вы писали:
VP>1. Где его создать и когда???
Синглтон с кешем RM'ов
VP>(ну это не очень мощная проблема, но новичка загоняет)
Значит надо поскорее переставать быть новичком.
VP>2. Где хранить ключи для получения ресурсов??? (GetString(key))
Что значит хранить? Прямо в коде, использующем эти ресурсы.
VP>3. Как быть когда ключы изменяются, добавляются и удаляются??? (менять константы в коде — copy+paste)
Ключи на то они и ключи, что меняются редко. Это практически имена переменных.
VP>4. Как сдержать нервы после первых трех пунктов?? (это все рутина которую разработчик пытается устранить написав генерилку)
Ты меня измени, но у меня такой чувство что ты болен юношеским максимализмом..
На этом мы и занкончим...
Я давно уже не новичок в нете (это так к сведению).
Я тебе могу привести кучу примеров когда ты один пишешь весь код у тебя все нормально, только потому, что ты один. А вот когда приходят (пи пи пи) зеленые, вот они горазды на такие выдумки, что ты себе предсавить не сможешь. Так вот по этой причине и раждаются runtime ошибки. Только по тому что, один заюзал константу а второй её в русурсном файле изменил. В таких случаях на этапе компиляции такие ошибки не словишь.
Здравствуйте, V.Petrovski, Вы писали:
VP>Здравствуйте, AndrewVK, Вы писали:
VP>Ты меня измени, но у меня такой чувство что ты болен юношеским максимализмом.. VP>На этом мы и занкончим... VP>Я давно уже не новичок в нете (это так к сведению).
VP>Я тебе могу привести кучу примеров когда ты один пишешь весь код у тебя все нормально, только потому, что ты один. А вот когда приходят (пи пи пи) зеленые, вот они горазды на такие выдумки, что ты себе предсавить не сможешь. Так вот по этой причине и раждаются runtime ошибки. Только по тому что, один заюзал константу а второй её в русурсном файле изменил. В таких случаях на этапе компиляции такие ошибки не словишь.
Что-то я вообще ничего не понимаю. Каким образом ты собираешься считывать данные в константу из ресурсов? И что конкретно ты в ресурсах хранишь — откуда рантайм ошибки? Ресурсы в первую очередь предназначены для хранения локализуемых стрингов. И что это за пи-пи-пи зеленые, которые у тебя в ресурсы лезут? Они что по совместительству и специалисты по языкам?
После долгих раздумий (с пару месяцев), предложу несколько приемов:
1. Создать класс LocalizationService, который будет заведовать ресурсами в зависимости от CurrentCultureInfo.
Т.е. он должен содержать в себе (или вызывать у CurrentLocalization) ту самую функцию GetString.
2. Создать класс LocalizedString, приводящийся к строке. В момент приведения она вызывает LocalizationService.GetString
(...) или Localization.Current.GetString(...). В конструктор этой строке передавать алиас. Все такие строки
включить как readonly в соответствующие классы — генератором или руками.
3. Можно вместо алиаса передавать в LocalizedString еще и имя словаря. Наличие словаря проверять в конструкторе. Там же
проверять наличие в словаре такого алиаса. 10 000 проверок при старте никого не напрягут.
4. Написать к студии Add-in, генерящий код класса, типа SR по словарю и редактирующий этот словарь. Чувак вернул в проект
поправленный словарь -> код SR пересобрался, появились/исчезли LocalizedString -> получили ошибку компиляции.
Здравствуйте, V.Petrovski, Вы писали:
VP>Ты меня измени, но у меня такой чувство что ты болен юношеским максимализмом.. VP>На этом мы и занкончим... VP>Я давно уже не новичок в нете (это так к сведению).
Здравствуйте, Воронков Василий, Вы писали:
ВВ>Здравствуйте, V.Petrovski, Вы писали:
ВВ> ВВ> Что-то я вообще ничего не понимаю. Каким образом ты собираешься считывать данные в константу из ресурсов? И что конкретно ты в ресурсах хранишь — откуда рантайм ошибки? Ресурсы в первую очередь предназначены для хранения локализуемых стрингов. И что это за пи-пи-пи зеленые, которые у тебя в ресурсы лезут? Они что по совместительству и специалисты по языкам?
Здравствуйте, V.Petrovski, Вы писали:
VP>Вот тебе пример
VP>
VP>...
VP>internal string const FooterMask = "FooterMask";
Хм, я не совсем правильно понял, что ты в данном случае имел в виду под констами. Я подумал, что речь идет о считывании содержимого ресурсов в константу :) .Но все же непонятно немного, зачем использовать дополнительную конст в данном случае? Не проще ли сразу писать название поле при GetString? Хотя это детали.
VP>...
VP>public string Footer
VP>{
VP> get
VP> {
VP> return String.Format(resourceManager.GetString(FooterMask), CurrentPage, Count);
VP> }
VP>}
VP>...
VP>
VP>а вот ресурс VP>
VP>FooterMasc = Page {0} of {1}
VP>и что произойдет при обращении и свойству Footer?
И что произойдет? Мне кажется это довольно надуманная проблема. Если ты действительно сталкивался с подобной ситуацией, то тогда извини. Но я не понимаю, каким образом человек будет изменять поля в ресурснике, которые не он сам создал? Ведь ежу понятно, что если поле создано до него, к тому же с символу для стрингформата, значит оно где-то уже используется. И если этот человек все же решает его изменить, то он или занимается намеренным зловредительством или у него не в порядке с головой.
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, V.Petrovski, Вы писали:
AVK>Если есть что по делу — говори, а рассказывать всем какой ты умный и какие все вокруг дураки не стоит.
Ты на первый пост посмотри. Меня интересует как это делает не только Microsoft, а например 9rays или любые другие конторы который пишут под .NET.
Здравствуйте, V.Petrovski, Вы писали:
VP>Ты на первый пост посмотри. Меня интересует как это делает не только Microsoft, а например 9rays или любые другие конторы который пишут под .NET.
Я тебе предложил посмотреть как это сделано в янусе. Проблем при использовании пока не замечено.
выкинет исключение. И вообще человек не машина, неужели ты никогда не делал опечаток при написании программы? Но тебя спасал компилятор, а здесь ты об "опечатке" узнаешь только в рантайме.
Показатель. Попробуй попасть хотя бы в первую десятку, а потом уж будешь разговаривать с другими с видом доки. Да, позвольте кстати поинтересоваться завершенными Вами проектами?
VP> ну тогда ...
Здравствуйте, AndrewVK, Вы писали:
AVK>Я тебе предложил посмотреть как это сделано в янусе. Проблем при использовании пока не замечено.
И какую версию? у меня сам видешь какая. В этой что у меня у вас может где и используется ResourceManager, но в настройках приложения у вас зашиты напрымую русские строки для аттрибутов (Decription,DicplayName,Category).
Здравствуйте, AndrewVK, Вы писали:
AVK>Показатель. Попробуй попасть хотя бы в первую десятку, а потом уж будешь разговаривать с другими с видом доки. Да, позвольте кстати поинтересоваться завершенными Вами проектами?
Здравствуйте, V.Petrovski, Вы писали:
AVK>>Я тебе предложил посмотреть как это сделано в янусе. Проблем при использовании пока не замечено.
VP>И какую версию?
Здравствуйте, AndrewVK, Вы писали:
AVK>Ну тогда что ты в этом болоте делаешь? AVK>Нет, но с какой это стати ты разговариваешь со мной с позиций старшего товарища?
Если обидел, то извини. Но я много где видел ответ от тебя следующего шаблона
return String.Format("Ответ на вопрос ""{0}"" в исходниках януса", question);
Просто не знаешь где наедешь где потеряешь ... весь смысл в познании.
VP> throw new ParseException("Invalid value format",ex);
VP>
Я как-то изобрёл свой способ:
throw new ParseException(ResStrings.GetString("Invalid value format"),ex);
Класс ResStrings использует передаваемую строку как ключ и по ней ищет в каких-то своих закромах русский вариант. Если же русского варианта нет, используется непосредственно Invalida value format.
Соответственно, после написания самой программы, нужно пройтись и поиском повыклёвывать строчки вида "ResStrings.GetString(", создать заготовку и перевести разом все сообщения:
public class ResStrings
{
static readonly Hashtable strings=new Hashtable();
static ResStrings()
{
// В этом методе генерируются строки для переводов всех сообщений.
// После перевода должно быть так:
strings["Invalid value format"]="Неправильный формат значения";
// А сама заготовка должна выглядеть примерно так:
strings["Invalid version"] ="Invalid version";
strings["Bad row number"] ="Bad row number";
strings["Message failed"] ="Message failed";
...
}
public static string GetString(string englishKey)
{
string result=strings[englishKey] as string;
if( result==null )
return englishKey;
else
return result;
}
}
Ну, в данном случае ResStrings реализован вообще без ресурсов. Можно просто выделить его в отдельную сборку и так подключать.
Если в процессе разработки какой-нибудь горе-программист забудет добавить русский перевод для
Здравствуйте, mihailik, Вы писали:
M>Соответственно, после написания самой программы, нужно пройтись и поиском повыклёвывать строчки вида "ResStrings.GetString(", создать заготовку и перевести разом все сообщения:
Я бы посоветовал не изобретать велосипед и использовать класс ResourceManager
Здравствуйте, V.Petrovski, Вы писали:
VP>По поводу визуальной части вроде все ясно VP>1. Ставишь свойство Localizable в true VP>2. Выбираешь нужный Language и локализуешь
Можно насчёт этого по-подробнее, пожайлуста.
Здравствуйте, maloyDS, Вы писали:
DS>Здравствуйте, V.Petrovski, Вы писали:
VP>>По поводу визуальной части вроде все ясно VP>>1. Ставишь свойство Localizable в true VP>>2. Выбираешь нужный Language и локализуешь DS>Можно насчёт этого по-подробнее, пожайлуста. Зри в корень
Здравствуйте, V.Petrovski, Вы писали:
DS>>Можно насчёт этого по-подробнее, пожайлуста. VP>Зри в корень
Спасибо, жутко интересно, но плохо понятно
Может кто коротко ответит у меня такая проблема, размещаю, например, кнопку на форме, делаю её Caption на русском языке, а при запуске вместо русского ерунда всякая.
Здравствуйте, V.Petrovski, Вы писали:
VP>Такой подход для визуальной части, как сие для бизнес логики замутить получше?
Ты внимательно читал? Да и АВК тебе ровно про тоже говорил. Просто тебе почему-то не понравился этот подход и ты встал в позу. Ну, тогда рожай велосипед, что воду то зря мутить?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, V.Petrovski, Вы писали:
VP>выкинет исключение. И вообще человек не машина, неужели ты никогда не делал опечаток при написании программы? Но тебя спасал компилятор, а здесь ты об "опечатке" узнаешь только в рантайме.
Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте, V.Petrovski, Вы писали:
VP>>Такой подход для визуальной части, как сие для бизнес логики замутить получше?
VD>Ты внимательно читал? Да и АВК тебе ровно про тоже говорил. Просто тебе почему-то не понравился этот подход и ты встал в позу. Ну, тогда рожай велосипед, что воду то зря мутить?
Я велоспипед не рожаю.
А по поводу этого подхода, ради интереса посмотри как сделана локализация в Framework.NET или в ROTOR.
Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте, V.Petrovski, Вы писали:
VP>>Такой подход для визуальной части, как сие для бизнес логики замутить получше?
VD>Ты внимательно читал? Да и АВК тебе ровно про тоже говорил. Просто тебе почему-то не понравился этот подход и ты встал в позу. Ну, тогда рожай велосипед, что воду то зря мутить?
Я велоспипед не рожаю.
А по поводу этого подхода, ради интереса посмотри как сделана локализация в Framework.NET или в ROTOR.
Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте, V.Petrovski, Вы писали:
VP>>выкинет исключение. И вообще человек не машина, неужели ты никогда не делал опечаток при написании программы? Но тебя спасал компилятор, а здесь ты об "опечатке" узнаешь только в рантайме.
VD>А вот так не пробовал?
VD>Да и вместо Format-а можно применять Replase. Тогда ошибок не будет.
VD>В общем, у тебя какие-то личные проблемы которые ты пытаешся приписать МС.
И это по твоему правильная реализация??? И что увидит пользователь в случае ошибки?
Не важно русский, японец или балгар —
"Неверный формат ресурсов: " + ex.Message
И нецжели приятно видеть такие вот месаги (пример WinCMD)?
Здравствуйте, V.Petrovski, Вы писали:
VD>>В общем, у тебя какие-то личные проблемы которые ты пытаешся приписать МС. VP>И это по твоему правильная реализация??? И что увидит пользователь в случае ошибки? VP>Не важно русский, японец или балгар —
VP>
VP>"Неверный формат ресурсов: " + ex.Message
Это сообщение должно вылезать только в самом крайнем случае. И не надо себе заморачивать голову красотой в подвале. Ты основной кода сделай красивым.
VP>И нецжели приятно видеть такие вот месаги (пример WinCMD)?
VP>
VP>Руccий message не найден.
Да выдавай. Только если ты ограничишся только этим сообщением, то пользователь вообще не поймет в чем проблема, а человек которому придется принимать багрепорт и искать ошибку не сможет ее локализовать и устранить. Зто называется шетишизм, т.е. когда вместо полезной программы пишится "правильная" программа. Оно тебе надо?
... << RSDN@Home 1.1 beta 1 >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, V.Petrovski, Вы писали:
VP>Я велоспипед не рожаю. VP>А по поводу этого подхода, ради интереса посмотри как сделана локализация в Framework.NET или в ROTOR.
А ты думаешь тот же АВК откуда этот подход взял?
... << RSDN@Home 1.1 beta 1 >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, V.Petrovski, Вы писали:
VP>По поводу визуальной части вроде все ясно VP>1. Ставишь свойство Localizable в true VP>2. Выбираешь нужный Language и локализуешь VP>А вот как по поводу таких вещей VP>
VP>.....
VP>
VP>Я конечно же не стал изобретать велосипед, немного подточил gensr.pl что бы генерил более удобный для использования класс SR, но все же не покидует душу вопрос — Неужели нет другого механизма или способа для локализации кода????
Я хочу возобновить эту тему.
Мой вопрос заключается в следующем. На данный момент, IMHO, основной способ локализации — использование ResourceManager (либо напрямую, либо через обертки фреймфорков, например Spring.NET), который берет даные из resource-файлов, внедренных в сборки. Но дело в том, что если файлы ресурсов внедрены в сборки, то теряется некоторая гибкость. Например, необходимо поставить заказчику language pack — нужно заменять все сборки новыми, внутри которых есть нужные ресурсы. С другой стороны — если бы данные для локализации были представлены просто пачкой текстовых файлов messages<culture>.ini, то суть патча сводилась бы только к дополнению установленного приложения набором таких файлов. Отсюда — так ли уж действительно разумно использовать ResourceManager вместо _отдельных_ легко читаемых файлов?
Здравствуйте, ika, Вы писали:
ika>Я хочу возобновить эту тему. ika>Мой вопрос заключается в следующем. На данный момент, IMHO, основной способ локализации — использование ResourceManager (либо напрямую, либо через обертки фреймфорков, например Spring.NET), который берет даные из resource-файлов, внедренных в сборки. Но дело в том, что если файлы ресурсов внедрены в сборки, то теряется некоторая гибкость. Например, необходимо поставить заказчику language pack — нужно заменять все сборки новыми, внутри которых есть нужные ресурсы. С другой стороны — если бы данные для локализации были представлены просто пачкой текстовых файлов messages<culture>.ini, то суть патча сводилась бы только к дополнению установленного приложения набором таких файлов. Отсюда — так ли уж действительно разумно использовать ResourceManager вместо _отдельных_ легко читаемых файлов?
Не надо поставлять новые модулю достаточно в language pack включить Satellite Assemblies.
Для примера можешь посмотреть как делает MS language packs для .NET Framework.
В использовании ResourceManager есть только один недостаток, нельзя менять язык форм в runtime.
Здравствуйте, ika, Вы писали:
ika>Мой вопрос заключается в следующем. На данный момент, IMHO, основной способ локализации — использование ResourceManager (либо напрямую, либо через обертки фреймфорков, например Spring.NET), который берет даные из resource-файлов, внедренных в сборки.
Почитай про сателлитные сборки (satellite assemblies). Все совсем не так. как далее описано в посте.
Здравствуйте, ika, Вы писали:
ika>Мой вопрос заключается в следующем. На данный момент, IMHO, основной способ локализации — использование ResourceManager (либо напрямую, либо через обертки фреймфорков, например Spring.NET), который берет даные из resource-файлов, внедренных в сборки. Но дело в том, что если файлы ресурсов внедрены в сборки, то теряется некоторая гибкость. Например, необходимо поставить заказчику language pack — нужно заменять все сборки новыми, внутри которых есть нужные ресурсы. С другой стороны — если бы данные для локализации были представлены просто пачкой текстовых файлов messages<culture>.ini, то суть патча сводилась бы только к дополнению установленного приложения набором таких файлов. Отсюда — так ли уж действительно разумно использовать ResourceManager вместо _отдельных_ легко читаемых файлов?
Можно делать отдельную сборку с ресурсами. Единственный недостаток ResourceManager'а — он генерит internal класс для типизированного доступа к ресурсам. Я для таких целей напиал AddIn, который меняет область видимости на public и позволяет делать поиск/добавление/изменение реурсов; очень удобно. Потом просто переводишь ресурсы сборки на нужные языки и пользуешь.
Че-то там много всего написано...
Делаешь обычный проект, библиотеку, который содержит только файл ресурсов. В этом же проекте (все в IDE) плодишь столько *.LANG-LANG.resx файлов, сколько надо. При компиле тебе создадутся отдельные сборки для каждого языка. Вот и все.
Мне немного пришлось повозиться с AddIn'ом (особенно с разгребанием COFF имиджа) для удобной работы с ресурсами . За то теперь —
Здравствуйте, ika, Вы писали:
ika>Если локализация через satellite assemblies действительно требует таких вещей, то работа с текстовыми файлами resources.<culture>.ini кажется мне гораздо проще и надежней. Если бы еще можно было их подружить с ResourceManager, было бы вообще супер.
Надо учитывать, что все в Framework'e максимально универсально! Твой вариант не позволит локализовать картинки или еще какой ресурс, например, звуковой файл.
Есть файл текстовый SR.strings, для него настроен custom tool: String Resource Tool
В него складывают все строки:
[strings]
Raw = Raw string
WithArgs(a,b) = First argument {0}, Second argument {1}
WithTypedArgs(int a, string b) = Integer arg {0}, string arg {2}
MultiLine(c,d) = First Line {0}
= Second Line {1}
[strings.de]
Raw = German string
custom tool генерит resx и соотв. класс для доступа где строки без параметров будут полями а с параметрами — методами. Откуда все вытекающие преимущества — автокомплит констант для строк, проверка на ошибки.
здесь о том что зарелизили этот tool и ссылка где взять
Если используете EntLib то недавно появился отдельный блок здесь умеющий тянуть ресурсы не только строковые и откуда угодно, для строк же IMHO String Resource Tool это пэсня
Здравствуйте, AlexZu, Вы писали:
AZ>Альтернативная реализация может быт ьнайдена здесь String Resource Generator (включая command line утилиту, исходники).
Кстати да, мы пользовались ею когда разработчики из EntLib еще не выложили String Resource Tool.