c# .net localization multilanguage

c# - La mejor forma de implementar multi-idioma/globalización en un gran proyecto.NET



localization multilanguage (10)

+1 base de datos

Los formularios en su aplicación incluso pueden volver a traducirse sobre la marcha si se realizan correcciones en la base de datos.

Usamos un sistema donde todos los controles se asignaron en un archivo XML (uno por formulario) a los ID de recursos de lenguaje, pero todos los ID estaban en la base de datos.

Básicamente, en lugar de que cada control tenga la ID (implementando una interfaz, o usando la propiedad de etiqueta en VB6), usamos el hecho de que en .NET, el árbol de control era fácilmente detectable a través de la reflexión. Un proceso en el que el formulario cargado crearía el archivo XML si faltaba. El archivo XML correlacionaría los controles con sus ID de recursos, por lo que esto simplemente tenía que completarse y correlacionarse con la base de datos. Esto significaba que no era necesario cambiar el binario compilado si algo no estaba etiquetado, o si debía dividirse en otra ID (algunas palabras en inglés que podrían usarse como sustantivos y verbos podrían necesitar traducir a dos palabras diferentes) en el diccionario y no ser reutilizado, pero es posible que no descubras esto durante la asignación inicial de los ID). Pero el hecho es que todo el proceso de traducción se vuelve completamente independiente de tu binario (cada forma tiene que heredar de una forma base que sepa cómo traducirse a sí misma y a todos sus controles).

Los únicos en los que la aplicación se involucra más es cuando se utiliza una fase con puntos de inserción.

El software de traducción de la base de datos fue su pantalla de mantenimiento CRUD básica con varias opciones de flujo de trabajo para facilitar el paso de las traducciones faltantes, etc.

Pronto trabajaré en un gran proyecto de c # y me gustaría crear un soporte multilingüe desde el principio. He tenido un juego y puedo hacerlo funcionar usando un archivo de recursos separado para cada idioma, luego uso un administrador de recursos para cargar las cadenas.

¿Hay algún otro enfoque bueno que pueda analizar?


La mayoría de los proyectos de código abierto usan GetText para este propósito. No sé cómo y si alguna vez se ha utilizado en un proyecto .Net.


No creo que haya una "mejor manera". Realmente dependerá de las tecnologías y el tipo de aplicación que esté creando.

Webapps puede almacenar la información en la base de datos como han sugerido otros carteles, pero recomiendo usar archivos de recursos independientes. Eso es archivos de recursos separados de su fuente . Los archivos de recursos separados reducen la contención de los mismos archivos y, a medida que crece el proyecto, es posible que la localización se realice por separado de la lógica empresarial. (Programadores y traductores).

Los gurús de Microsoft WinForm y WPF recomiendan utilizar conjuntos de recursos independientes personalizados para cada configuración regional.

La capacidad de WPF para clasificar los elementos de la interfaz de usuario para el contenido reduce el trabajo de diseño requerido, por ejemplo: (las palabras en japonés son mucho más cortas que en inglés).

Si está considerando WPF: sugiero leer este artículo de msdn. Para ser sincero, encontré las herramientas de localización de WPF: msbuild, locbaml, (y tal vez una hoja de cálculo de Excel) tedioso de usar, pero funciona.

Algo relacionado solo un poco: un problema común que enfrento es la integración de sistemas heredados que envían mensajes de error (generalmente en inglés), no códigos de error. Esto fuerza los cambios en los sistemas heredados, o la asignación de cadenas de fondo a mis propios códigos de error y luego a cadenas localizadas ... yech. Los códigos de error son localizaciones amigo


Puede usar herramientas comerciales como Sisulizer . Creará un conjunto de satélites para cada idioma. Lo único que debe prestar atención no es ofuscar los nombres de las clases de formulario (si usa el ofuscador).


Usamos un proveedor personalizado para soporte multilingüe y ponemos todos los textos en una tabla de base de datos. Funciona bien, excepto que a veces enfrentamos problemas de almacenamiento en caché al actualizar textos en la base de datos sin actualizar la aplicación web.


Los archivos de recursos estándar son más fáciles. Sin embargo, si tiene datos dependientes del idioma, como tablas de búsqueda, tendrá que administrar dos conjuntos de recursos.

No lo he hecho, pero en mi próximo proyecto implementaría un proveedor de recursos de base de datos. Encontré cómo hacerlo en MSDN:

http://msdn.microsoft.com/en-us/library/aa905797.aspx

También encontré esta implementación:

Proveedor de DBResource


He estado buscando y he encontrado esto:

Si usa WPF o Silverlight, su enfoque podría ser usar WPF LocalizationExtension por muchas razones.

IT''s Open Source Es GRATIS (y permanecerá gratis) en un estado real de estabilidad

En una aplicación de Windows, podrías hacer algo como esto:

public partial class App : Application { public App() { } protected override void OnStartup(StartupEventArgs e) { Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("de-DE"); ; Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("de-DE"); ; FrameworkElement.LanguageProperty.OverrideMetadata( typeof(FrameworkElement), new FrameworkPropertyMetadata( XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag))); base.OnStartup(e); } }

Y creo que en una página Wep el enfoque podría ser el mismo.

¡Buena suerte!


He visto proyectos implementados usando varios enfoques diferentes, cada uno tiene sus ventajas y desventajas.

  • Uno lo hizo en el archivo de configuración (no es mi favorito)
  • Uno lo hizo usando una base de datos, esto funcionó bastante bien, pero fue un dolor para usted saber qué mantener.
  • Uno usó archivos de recursos de la manera que está sugiriendo y debo decir que fue mi enfoque favorito.
  • El más básico lo hizo usando un archivo de inclusión lleno de cadenas, feo.

Yo diría que el método de recursos que has elegido tiene mucho sentido. Sería interesante ver las respuestas de otras personas también, ya que a menudo me pregunto si hay una forma mejor de hacer cosas como esta. He visto numerosos recursos que apuntan al método de usar recursos, incluido uno aquí en SO .


Me gustaría ir con los múltiples archivos de recursos. No debería ser tan difícil de configurar. De hecho, recientemente respondí una pregunta similar sobre la configuración de archivos de recursos basados ​​en un lenguaje global junto con archivos de recursos de lenguaje de formularios.

Localización en Visual Studio 2008

Considero que el mejor enfoque, al menos para el desarrollo de WinForm.


Use un proyecto separado con Recursos

Puedo decir esto desde mi experiencia, con una solución actual con 12 proyectos que incluyen API, MVC, bibliotecas de proyectos (funcionalidades principales) y WPF. Todavía no lo he probado con bibliotecas portátiles porque no creé una biblioteca portátil para la biblioteca de idiomas.

Vamos a por ello.

Pro''s

  • Fuertemente escrito en casi todas partes.
  • En WPF no tiene que tratar con ResourceDirectories .
  • Compatible con ASP.NET, Class Libraries y WPF por lo que he probado.
  • No se necesitan bibliotecas adicionales de terceros.
  • Apoya la recuperación de la cultura: en-US -> en.
  • No solo back-end, también funciona en XAML para WPF, en .cshtml para MVC.
  • Thread.CurrentThread.CurrentCulture fácilmente el idioma cambiando el Thread.CurrentThread.CurrentCulture
  • Los motores de búsqueda pueden rastrear en diferentes idiomas y el usuario puede enviar o guardar direcciones URL específicas del idioma.

Contras

  • WPF XAML a veces tiene errores, las cadenas recién agregadas no se muestran directamente. Rebuild es la solución temporal (vs2015).
  • Dime.

Preparar

Cree un proyecto de idioma en su solución, asígnele un nombre como MyProject.Language . Agregue una carpeta llamada Recursos, y en esa carpeta, cree dos archivos de Recursos (.resx). Uno llamado Resources.resx y otro llamado Resources.en.resx (o .en-GB.resx para específicos). En mi implementación, tengo el lenguaje NL (holandés) como el idioma predeterminado, por lo que va en mi primer archivo, y el inglés va en mi segundo archivo.

La instalación debería verse así:

Las propiedades de Resources.resx deben ser:

Asegúrese de que el espacio de nombres de la herramienta personalizada esté configurado en el espacio de nombres de su proyecto. La razón de esto es que en WPF, no puede hacer referencia a Resources dentro de XAML.

Y dentro del archivo de recursos, establezca el modificador de acceso en Público:

Usar en otro proyecto

Referencia a su proyecto: haga clic con el botón derecho en Referencias -> Agregar referencia -> Printed / Solutions.

Use el espacio de nombres en un archivo: using MyProject.Language;

Úselo como en back-end: string someText = Resources.orderGeneralError; Si hay algo más llamado Recursos, simplemente ingrese todo el espacio de nombres.

Usando en MVC

En MVC puede hacer lo que quiera para configurar el idioma, pero utilicé las URL parametrizadas, que pueden configurarse así:

RouteConfig.cs debajo de las otras asignaciones

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 (puede ser necesario agregarlo, si es así, agregue FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); al método Application_start() en Global.asax

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 simplemente establece la información de Cultura.

//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) { } }

Uso en .cshtml

@using MyProject.Language; <h3>@Resources.w_home_header</h3>

o si no desea definir los usos, simplemente complete el espacio de nombres completo O puede definir el espacio de nombres en /Views/web.config:

<system.web.webPages.razor> <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" /> <pages pageBaseType="System.Web.Mvc.WebViewPage"> <namespaces> ... <add namespace="MyProject.Language" /> </namespaces> </pages> </system.web.webPages.razor>

Este tutorial fuente de implementación de mvc: Awesome tutorial blog

Uso en bibliotecas de clase para modelos

El uso de back-end es el mismo, pero solo un ejemplo para usar en atributos

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; } } }

Si tiene Reacondicionador, comprobará automáticamente si existe el nombre de recurso proporcionado. Si prefiere seguridad tipo, puede usar plantillas T4 para generar una enumeración

Utilizando en WPF.

Por supuesto, agregue una referencia a su espacio de nombres MyProject.Language , sabemos cómo usarlo en el back-end.

En XAML, dentro del encabezado de una ventana o UserControl, agregue una referencia de espacio de nombres llamada lang así:

<UserControl x:Class="Babywatcher.App.Windows.Views.LoginView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:MyProject.App.Windows.Views" xmlns:lang="clr-namespace:MyProject.Language;assembly=MyProject.Language" <!--this one--> mc:Ignorable="d" d:DesignHeight="210" d:DesignWidth="300">

Luego, dentro de una etiqueta:

<Label x:Name="lblHeader" Content="{x:Static lang:Resources.w_home_header}" TextBlock.FontSize="20" HorizontalAlignment="Center"/>

Dado que está fuertemente tipado, está seguro de que existe la cadena de recursos. Es posible que deba recompilar el proyecto algunas veces durante la instalación, WPF a veces tiene fallas con espacios de nombres nuevos.

Una cosa más para WPF es establecer el idioma dentro de la App.xaml.cs . Puede hacer su propia implementación (elegir durante la instalación) o dejar que el sistema decida.

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; } } }

Ahí va, ahora puede usar un único archivo de recursos para todo su proyecto. Esto hace que sea muy fácil exportar todo a un documento distinto y dejar que alguien lo traduzca.