我将很快开始研究一个大型的c#项目,并希望从一开始就构建多语言支持.我有一个游戏,可以使用每种语言的单独资源文件,然后使用资源管理器加载字符串.
我还有其他可以研究的好方法吗?
我可以从经验中看出这一点,拥有12个 24项目的当前解决方案,包括API,MVC,项目库(核心功能),WPF和Xamarin.值得一读这篇长篇文章,因为我觉得这是最好的方法.在VS工具的帮助下,可以轻松导出和导入,发送给翻译机构或由其他人审核.
编辑02/2018:仍然很强大,将其转换为.NET标准库使得甚至可以在.NET Framework和.NET Core中使用它.我添加了一个额外的部分,用于将其转换为JSON,例如angular可以使用它.
编辑:2019:与Xamarin一起前进,这仍适用于所有平台.例如,Xamarin.Forms也建议使用resx文件.(我还没有在Xamarin.Forms中开发应用程序,但文档,这是详细的入门方式,涵盖了它:Xamarin.Forms文档).就像将它转换为JSON一样,我们也可以将它转换为Xamarin.Android的一个.xml文件(目前正在处理).
所以,让我们来做吧.
Pro的
几乎无处不在.
在WPF中,您无需处理.resw
.
据我测试,支持ASP.NET,类库,WPF,Xamarin,.NET Core,.NET Standard.
无需额外的第三方库.
支持文化回退:en-US - > en.
不仅是后端,也适用于WPF的XAML和MVC的.cshtml中的Xamarin.Forms.
通过改变来轻松操纵语言 ResourceDirectories
搜索引擎可以使用不同语言进行爬网,用户可以发送或保存特定于语言的网址.
反对的
WPF XAML有时会出错,新添加的字符串不会直接显示.重建是临时修复(vs2015).
告诉我.
建立
在解决方案中创建语言项目,为其命名,如MyProject.Language.添加一个名为Resources的文件夹,在该文件夹中创建两个Resources文件(.resx).一个名为Resources.resx,另一个名为Resources.en.resx(或特定的.en-GB.resx).在我的实现中,我使用NL(荷兰语)语言作为默认语言,因此在我的第一个文件中,英语在我的第二个文件中.
安装程序应如下所示:
Resources.resx的属性必须是:
确保将自定义工具命名空间设置为项目命名空间.原因是在WPF中,您无法引用Thread.CurrentThread.CurrentCulture
XAML内部.
在资源文件中,将访问修饰符设置为Public:
在另一个项目中使用
参考您的项目:右键单击References - > Add Reference - > Prjects\Solutions.
在文件中使用命名空间: Resources
在后端使用它如此:
using MyProject.Language;
如果有其他名为Resources的东西,那么只需放入整个命名空间.
在MVC中你可以做但是你喜欢设置语言,但是我使用了参数化的url,可以这样设置:
RouteConfig.cs 低于其他映射
routes.MapRoute( name: "Locolized", url: "{lang}/{controller}/{action}/{id}", constraints: new { lang = @"(\w{2})|(\w{2}-\w{2})" }, // en or en-US defaults: new { controller = "shop", action = "index", id = UrlParameter.Optional } );
FilterConfig.cs(可能需要添加,如果是这样,请添加string someText = Resources.orderGeneralError;
到FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
方法中)Application_start()
public class FilterConfig { public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new ErrorHandler.AiHandleErrorAttribute()); //filters.Add(new HandleErrorAttribute()); filters.Add(new LocalizationAttribute("nl-NL"), 0); } }
LocalizationAttribute
public class LocalizationAttribute : ActionFilterAttribute { private string _DefaultLanguage = "nl-NL"; private string[] allowedLanguages = { "nl", "en" }; public LocalizationAttribute(string defaultLanguage) { _DefaultLanguage = defaultLanguage; } public override void OnActionExecuting(ActionExecutingContext filterContext) { string lang = (string) filterContext.RouteData.Values["lang"] ?? _DefaultLanguage; LanguageHelper.SetLanguage(lang); } }
LanguageHelper只设置文化信息.
//fixed number and date format for now, this can be improved. public static void SetLanguage(LanguageEnum language) { string lang = ""; switch (language) { case LanguageEnum.NL: lang = "nl-NL"; break; case LanguageEnum.EN: lang = "en-GB"; break; case LanguageEnum.DE: lang = "de-DE"; break; } try { NumberFormatInfo numberInfo = CultureInfo.CreateSpecificCulture("nl-NL").NumberFormat; CultureInfo info = new CultureInfo(lang); info.NumberFormat = numberInfo; //later, we will if-else the language here info.DateTimeFormat.DateSeparator = "/"; info.DateTimeFormat.ShortDatePattern = "dd/MM/yyyy"; Thread.CurrentThread.CurrentUICulture = info; Thread.CurrentThread.CurrentCulture = info; } catch (Exception) { } }
在.cshtml中的用法
@using MyProject.Language;@Resources.w_home_header
或者如果您不想定义使用,那么只需填写整个命名空间,或者您可以在/Views/web.config下定义命名空间:
...
这个mvc实现源码教程:很棒的教程博客
在类库中使用模型
后端使用是相同的,但只是在属性中使用的示例
using MyProject.Language; namespace MyProject.Core.Models { public class RegisterViewModel { [Required(ErrorMessageResourceName = "accountEmailRequired", ErrorMessageResourceType = typeof(Resources))] [EmailAddress] [Display(Name = "Email")] public string Email { get; set; } } }
如果您有重塑器,它将自动检查给定的资源名称是否存在.如果您更喜欢类型安全,可以使用T4模板生成枚举
Ofcourse添加对MyProject.Language命名空间的引用,我们知道如何在后端使用它.
在XAML中,在Window或UserControl的标题内,添加一个名为Global.asax
like 的名称空间引用:
mc:Ignorable="d"
d:Design d:Design>
然后,在标签内:
由于它是强类型的,因此您确定资源字符串存在.您可能需要在安装过程中重新编译项目,WPF有时会出现新的命名空间.
WPF的另一件事,设置内部的语言lang
.您可以自己执行(在安装期间选择)或让系统决定.
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
SetLanguageDictionary();
}
private void SetLanguageDictionary()
{
switch (Thread.CurrentThread.CurrentCulture.ToString())
{
case "nl-NL":
MyProject.Language.Resources.Culture = new System.Globalization.CultureInfo("nl-NL");
break;
case "en-GB":
MyProject.Language.Resources.Culture = new System.Globalization.CultureInfo("en-GB");
break;
default://default english because there can be so many different system language, we rather fallback on english in this case.
MyProject.Language.Resources.Culture = new System.Globalization.CultureInfo("en-GB");
break;
}
}
}
在Angular中使用它(转换为JSON)
现在,将Angular这样的框架与组件结合起来更为常见,因此没有cshtml.翻译存储在json文件中,我不打算介绍它是如何工作的,但如果你想将它转换为JSON文件,那很简单,我使用T4模板脚本将Resources文件转换为json文件.我建议安装T4编辑器来阅读语法并正确使用它,因为您需要进行一些修改.
只需注意一件事:无法生成数据,复制数据,清理数据并为其他语言生成数据.因此,您必须将下面的代码复制到您拥有的语言中,并在"//在此处选择语言"之前更改条目.目前没有时间来解决这个问题,但可能会在以后更新(如果感兴趣).
路径:MyProject.Language/T4/CreateWebshopLocalizationEN.tt
using Windows.UI.Xaml.Resources; public class MyXamlResourceLoader : CustomXamlResourceLoader { protected override object GetResource(string resourceId, string objectType, string propertyName, string propertyType) { return MyProject.Language.Resources.ResourceManager.GetString(resourceId); } }
你去了,你现在可以为你的所有项目使用一个资源文件.这使得将所有内容导出到excl文档非常容易,并让某人翻译并再次导入.
我已经看到使用多种不同方法实施的项目,每种方法都有其优点和缺点.
一个人在配置文件中做到了(不是我最喜欢的)
一个人使用数据库做到了 - 这非常有效,但是你知道要维护什么是痛苦的.
一个人使用的资源文件就像你建议的那样,我不得不说这是我最喜欢的方法.
最基本的一个是使用一个充满字符串的包含文件 - 丑陋.
我会说你选择的资源方法很有意义.看到其他人的答案也会很有趣,因为我常常想知道是否有更好的办法来做这样的事情.我已经看到了许多资源都指向使用资源方法,包括一个就在SO上.
我认为没有"最佳方式".它实际上取决于您正在构建的技术和应用程序类型.
Webapps可以像其他海报建议的那样将信息存储在数据库中,但我建议使用单独的资源文件.这是与您的源分开的资源文件.单独的资源文件减少了对相同文件的争用,并且随着项目的增长,您可能会发现本地化将从业务逻辑中单独完成.(程序员和翻译).
Microsoft WinForm和WPF专家建议使用为每个语言环境定制的单独资源程序集.
WPF将UI元素的大小调整为内容的能力降低了所需的布局工作,例如:(日语单词比英语短得多).
如果您正在考虑WPF:我建议阅读这篇msdn文章 为了说实话,我发现WPF本地化工具:msbuild,locbaml,(也许是一个excel电子表格)使用起来很乏味,但确实有效.
只是略微相关的东西:我面临的一个常见问题是集成发送错误消息的遗留系统(通常是英文版),而不是错误代码.这会强制更改遗留系统,或将后端字符串映射到我自己的错误代码,然后映射到本地化字符串...... yech. 错误代码是本地化的朋友