这是可插组件本地化好的解决办法?
-
21-09-2019 - |
题
我问了一个问题以前它只有一个答案。我已经有一段时间了,现在玩这个周围,有一个计划,但希望一些反馈,如果它是一个好主意。
的问题:
我想要其中有一个名称(不变的,用于识别组件)将其名字在正消耗它的应用程序本地化的,而没有与DisplayName特性污染组件的模型的组分。该组件可以存在于一个单独的DLL和在运行时被动态加载。
我的感觉是,组件DLL应负责提供本地化的名称(这似乎是很好的封装),但消耗组件的应用应该是负责获取/使用本地化的名称(该组件有一个事实用于显示目的不同的名称是不是组件的一个问题,但“查看”使用该成分)的
在解决方案:
的资源添加到各组分的dll具有相同名称的文件中的分量类是英寸的字符串添加到用钥匙是该部件的名称的资源。
在应用程序中获取的本地化名称如下所示:
ExternalObject obj = GetExternalObject ();
ResourceManager manager = new ResourceManager (obj.GetType ());
string localisedName= manager.GetString (obj.Name);
此代码可能会在一个航向类被封装,但输送点。这似乎是工作,但它是一个好主意,或者是有这样做的更好/更标准的方式?
编辑:我要指出的是一两件事,我不知道如何使用此解决方案是资源必须在具有相同名称的类在文件中的.resx文件这使得它的工作,为资源文件可以从类型名称来识别。这是一样的本地化形式似乎工作,使视觉工作室放的.resx为cs文件,而这一切看上去不错的“子组件”。但视觉工作室则抛出一个警告(有关编辑资源是另一个项目的项目的一部分),如果我尝试编辑这个文件,这让我觉得,也许还有就是我应该做一些这方面的其他方式。
解决方案
我觉得你有正确的想法,但有更好的方式来做到这一点。
据推测,你有一个接口,即插组件器具。说,IPluggable:
interface IPluggable {
...
string LocalizedName {get;}
...
}
这是你的主要二进制文件,加载可插入组装,并使用反射IPluggable实例(我假定这就是你有GetExternalObject()
方法一样),然后使用LocalizedName
属性访问的本地化名称。 内的IPluggable实施方式中,创建一个ResourceManager
并从该可插入组件的RESX访问LocalizedName
。
什么你做得到的是在可插拔的组装行为的良好封装 - 它负责提供您的本地化名称,但它选择这样做,没有你的男人程序假设一个ResourceManager
可以创建访问本地化名。
其他提示
我有一个问题,前一段时间本地化枚举值的,我不知道这是否回答你的问题,但至少给你另一种方法来的想法。
通过创建自己的本地化属性发起者
/// <SUMMARY>
/// Attribute used for localization. Description field should contain a reference to the Resource file for correct localization
/// </SUMMARY>
public class LocalizationAttribute : Attribute
{
public LocalizationAttribute(string description)
{
this._description = description;
}
private string _description;
/// <SUMMARY>
/// Used to reference a resource key
/// </SUMMARY>
public string Description
{
get
{
return this._description;
}
}
}
从那里我创建枚举本身
[TypeConverter(typeof(EnumToLocalizedString))]
public enum ReviewReason
{
[LocalizationAttribute("ReviewReasonNewDocument")]
NewDocument = 1,
[LocalizationAttribute("ReviewReasonInternalAudit")]
InternalAudit = 2,
[LocalizationAttribute("ReviewReasonExternalAudit")]
ExternalAudit = 3,
[LocalizationAttribute("ReviewReasonChangedWorkBehaviour")]
ChangedWorkBehaviour = 4,
[LocalizationAttribute("ReviewReasonChangedWorkBehaviourBecauseOfComplaints")]
ChangedWorkBehaviourBecauseOfComplaints = 5,
[LocalizationAttribute("ReviewReasonMovedFromOlderSystem")]
MovedFromOlderSystem = 6,
[LocalizationAttribute("ReviewReasonPeriodicUpdate")]
PeriodicUpdate = 7,
[LocalizationAttribute("ReviewReasonDocumentChanged")]
DocumentChanged = 8
}
然后创建了一个类型的转换器,其将获取LocalizationAttribute描述密钥和访问资源文件,以获取本地化(属性描述必须的资源键:)匹配)
public class EnumToLocalizedString : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return (sourceType.Equals(typeof(Enum)));
}
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
return (destinationType.Equals(typeof(String)));
}
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{
return base.ConvertFrom(context, culture, value);
}
public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
{
if (!destinationType.Equals(typeof(String)))
{
throw new ArgumentException("Can only convert to string.", "destinationType");
}
if (!value.GetType().BaseType.Equals(typeof(Enum)))
{
throw new ArgumentException("Can only convert an instance of enum.", "value");
}
string name = value.ToString();
object[] attrs = value.GetType().GetField(name).GetCustomAttributes(typeof(LocalizationAttribute), false);
if (attrs.Length != 1 !(attrs[0] is LocalizationAttribute))
{
throw new ArgumentException("Invalid enum argument");
}
return Handbok.Code.Resources.handbok.ResourceManager.GetString(((LocalizationAttribute)attrs[0]).Description);
}
}
最后我创建它使用的TypeConverter,在这种情况下是一个集合的客户端
public class ReviewReasonCollection
{
private static Collection<KEYVALUEPAIR<REVIEWREASON,>> _reviewReasons;
public static Collection<KEYVALUEPAIR<REVIEWREASON,>> AllReviewReasons
{
get
{
if (_reviewReasons == null)
{
_reviewReasons = new Collection<KEYVALUEPAIR<REVIEWREASON,>>();
TypeConverter t = TypeDescriptor.GetConverter(typeof(ReviewReason));
foreach (ReviewReason reviewReason in Enum.GetValues(typeof(ReviewReason)))
{
_reviewReasons.Add(new KeyValuePair<REVIEWREASON,>(reviewReason, t.ConvertToString(reviewReason)));
}
}
return _reviewReasons;
}
}
}
我本来贴在我的博客此解决方案。希望它可以帮助你:)
与您建议的方式的问题在于,它的将是难以更新的翻译,它甚至可能需要一个程序员。另外你怎么不更新整个应用程序更新翻译?
我已经做了很多翻译应用程序,而我所做的就是与格式化像这样translatations一个单独的文本文件:
[英文版]结果 DONE =完成
[挪威],点击 做= Ferdig
和我有一个名为TranslateForm(),我称之为形式显示事件中的功能,将所有的UI元素翻译。所述TranslateForm()函数将有事情等
buttonDone.Text = Translate.GetTranslation("Done");
与TranslateForm最后一部分是不是一个最佳的解决方案,我想随着时间的推移,我将迁移到一个解决方案,其中控制本身调用翻译类。 使用该系统的优点是其对程序设计师简单的,你可以有其他的脂肪酶添加翻译无需你以后做手工工作(这是importent给我,因为我有社区驱动的翻译),所以他们经常更新,我不想花时间上。 我还可以更新应用程序运行时翻译,而不必重新启动或更新的应用程序。