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

86

Pronto estaré trabajando en un gran proyecto de c # y me gustaría incorporar soporte en varios idiomas desde el principio. He jugado y puedo hacer que funcione usando un archivo de recursos separado para cada idioma, luego uso un administrador de recursos para cargar las cadenas.

¿Hay otros buenos enfoques que pueda considerar?

tjjjohnson
fuente

Respuestas:

88

Use un proyecto separado con Recursos

Puedo decir esto por nuestra experiencia, teniendo una solución actual con 12 24 proyectos que incluye API, MVC, Bibliotecas de proyectos (funcionalidades principales), WPF, UWP y Xamarin. Vale la pena leer este extenso post porque creo que es la mejor manera de hacerlo. Con la ayuda de herramientas VS fácilmente exportables e importables para ser enviadas a agencias de traducción o revisadas por otras personas.

EDITAR 02/2018: Aún siendo fuerte, convertirlo a una biblioteca .NET Standard hace posible incluso usarlo en .NET Framework y NET Core. Agregué una sección adicional para convertirlo a JSON para que, por ejemplo, angular pueda usarlo.

EDITAR 2019: en el futuro con Xamarin, esto todavía funciona en todas las plataformas. Por ejemplo, Xamarin.Forms recomienda usar archivos resx también. (Todavía no desarrollé una aplicación en Xamarin.Forms, pero la documentación, que es muy detallada para comenzar, la cubre: Documentación de Xamarin.Forms ). Al igual que convertirlo a JSON, también podemos convertirlo en un archivo .xml para Xamarin.Android.

EDITAR 2019 (2): Al actualizar a UWP desde WPF, encontré que en UWP prefieren usar otro tipo de archivo .resw, que es idéntico en términos de contenido pero el uso es diferente. Encontré una forma diferente de hacer esto que, en mi opinión, funciona mejor que la solución predeterminada .

EDITAR 2020: se actualizaron algunas sugerencias para proyectos más grandes (modulares) que pueden requerir proyectos en varios idiomas.

Vamos a por ello.

Pro's

  • Fuertemente mecanografiado en casi todas partes.
  • En WPF no tienes que lidiar con ResourceDirectories.
  • Compatible con ASP.NET, bibliotecas de clases, WPF, Xamarin, .NET Core, .NET Standard hasta donde he probado.
  • No se necesitan bibliotecas de terceros adicionales.
  • Admite respaldo cultural: en-US -> en.
  • No solo back-end, también funciona en XAML para WPF y Xamarin.Forms, en .cshtml para MVC.
  • Manipule 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 URL específicas del idioma.

Contras

  • WPF XAML a veces tiene errores, las cadenas recién agregadas no se muestran directamente. Reconstruir es la solución temporal (frente a 2015).
  • UWP XAML no muestra sugerencias de intellisense y no muestra el texto durante el diseño.
  • Dime.

Preparar

Cree un proyecto de lenguaje 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 idioma NL (holandés) como idioma predeterminado, por lo que va en mi primer archivo y el inglés en mi segundo archivo.

La configuración debería verse así:

proyecto de configuración de idioma

Las propiedades de Resources.resx deben ser: propiedades

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 Resourcesdentro de XAML.

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

modificador de acceso

Si tiene una aplicación tan grande (digamos diferentes módulos), puede considerar la posibilidad de crear varios proyectos como el anterior. En ese caso, puede prefijar sus claves y clases de recursos con el módulo en particular. Utilice el mejor editor de idioma que existe para Visual Studio para combinar todos los archivos en una sola descripción general.

Usar en otro proyecto

Referencia a su proyecto: haga clic con el botón derecho en Referencias -> Agregar referencia -> Proyectos \ Soluciones.

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

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

Usando en MVC

En MVC puede hacer lo que quiera para configurar el idioma, pero utilicé URL parametrizadas, que se pueden configurar 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 (es posible que deba agregarse, si es así, agréguelo FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);al Application_start()método enGlobal.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 solo 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 usos, simplemente complete todo el espacio de nombres 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 de la fuente de implementación de mvc: blog de tutoriales impresionante

Uso de bibliotecas de clases 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 remodelador, comprobará automáticamente si existe el nombre del recurso dado. Si prefiere la seguridad de tipos, 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 langasí:

<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 la cadena de recursos existe. Es posible que deba volver a compilar el proyecto a veces durante la configuración, WPF a veces tiene errores con nuevos espacios de nombres.

Una cosa más para WPF, configure el idioma dentro de 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;
        }
       
    }
}

Utilizando en UWP

En UWP, Microsoft usa esta solución , lo que significa que deberá crear nuevos archivos de recursos. Además, tampoco puede reutilizar el texto porque quieren que establezca el valor x:Uidde su control en XAML en una clave en sus recursos. Y en tus recursos tienes que hacer Example.Textpara completar un TextBlocktexto. No me gustó esa solución en absoluto porque quiero reutilizar mis archivos de recursos. Finalmente se me ocurrió la siguiente solución. Me acabo de enterar de esto hoy (2019-09-26), así que podría volver con algo más si resulta que esto no funciona como se desea.

Agregue esto a su proyecto:

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

Agregue esto App.xaml.csen el constructor:

CustomXamlResourceLoader.Current = new MyXamlResourceLoader();

Donde quiera que quiera en su aplicación, use esto para cambiar el idioma:

ApplicationLanguages.PrimaryLanguageOverride = "nl";
Frame.Navigate(this.GetType());

La última línea es necesaria para actualizar la interfaz de usuario. Mientras todavía estoy trabajando en este proyecto, noté que necesitaba hacer esto 2 veces. Podría terminar con una selección de idioma la primera vez que el usuario inicia. Pero dado que esto se distribuirá a través de la Tienda Windows, el idioma suele ser el mismo que el del sistema.

Luego use en XAML:

<TextBlock Text="{CustomResource ExampleResourceKey}"></TextBlock>

Usándolo en Angular (convertir a JSON)

Hoy en día es más común tener un marco como Angular en combinación con componentes, por lo que sin cshtml. Las traducciones se almacenan en archivos json, no voy a explicar cómo funciona, solo recomendaría encarecidamente ngx-translate en lugar de la traducción múltiple angular. Entonces, si desea convertir traducciones a un archivo JSON, es bastante fácil, utilizo un script de plantilla T4 que convierte el archivo de recursos en un archivo json. Recomiendo instalar el editor T4 para leer la sintaxis y usarlo correctamente porque necesita hacer algunas modificaciones.

Solo una cosa a tener en cuenta: no es posible generar los datos, copiarlos, limpiar los datos y generarlos para otro idioma. Por lo tanto, debe copiar el código a continuación tantas veces como idiomas tenga y cambiar la entrada antes de '// elegir idioma aquí'. Actualmente no hay tiempo para arreglar esto, pero probablemente se actualice más tarde (si está interesado).

Ruta: MyProject.Language / T4 / CreateLocalizationEN.tt

<#@ template debug="false" hostspecific="true" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ assembly name="System.Windows.Forms" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.Resources" #>
<#@ import namespace="System.Collections" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.ComponentModel.Design" #>
<#@ output extension=".json" #>
<#


var fileNameNl = "../Resources/Resources.resx";
var fileNameEn = "../Resources/Resources.en.resx";
var fileNameDe = "../Resources/Resources.de.resx";
var fileNameTr = "../Resources/Resources.tr.resx";

var fileResultName = "../T4/CreateLocalizationEN.json";//choose language here
var fileResultPath = Path.Combine(Path.GetDirectoryName(this.Host.ResolvePath("")), "MyProject.Language", fileResultName);
//var fileDestinationPath = "../../MyProject.Web/ClientApp/app/i18n/";

var fileNameDestNl = "nl.json";
var fileNameDestEn = "en.json";
var fileNameDestDe = "de.json";
var fileNameDestTr = "tr.json";

var pathBaseDestination = Directory.GetParent(Directory.GetParent(this.Host.ResolvePath("")).ToString()).ToString();

string[] fileNamesResx = new string[] {fileNameEn }; //choose language here
string[] fileNamesDest = new string[] {fileNameDestEn }; //choose language here

for(int x = 0; x < fileNamesResx.Length; x++)
{
    var currentFileNameResx = fileNamesResx[x];
    var currentFileNameDest = fileNamesDest[x];
    var currentPathResx = Path.Combine(Path.GetDirectoryName(this.Host.ResolvePath("")), "MyProject.Language", currentFileNameResx);
    var currentPathDest =pathBaseDestination + "/MyProject.Web/ClientApp/app/i18n/" + currentFileNameDest;
    using(var reader = new ResXResourceReader(currentPathResx))
    {
        reader.UseResXDataNodes = true;
#>
        {
<#
            foreach(DictionaryEntry entry in reader)
            {
                var name = entry.Key;
                var node = (ResXDataNode)entry.Value;
                var value = node.GetValue((ITypeResolutionService) null); 
                 if (!String.IsNullOrEmpty(value.ToString())) value = value.ToString().Replace("\n", "");
                 if (!String.IsNullOrEmpty(value.ToString())) value = value.ToString().Replace("\r", "");
#>
            "<#=name#>": "<#=value#>",
<#

    
            }
#>
        "WEBSHOP_LASTELEMENT": "just ignore this, for testing purpose"
        }
<#
    }
    File.Copy(fileResultPath, currentPathDest, true);
}


#>

Si tiene una aplicación modulair y siguió mi sugerencia de crear proyectos en varios idiomas, tendrá que crear un archivo T4 para cada uno de ellos. Asegúrese de que los archivos json estén definidos lógicamente, no tiene que estarlo en.json, también puede estarlo example-en.json. Para combinar varios archivos json para usar con ngx-translate , siga las instrucciones aquí

Usar en Xamarin.Android

Como se explicó anteriormente en las actualizaciones, uso el mismo método que he hecho con Angular / JSON. Pero Android usa archivos XML, así que escribí un archivo T4 que genera esos archivos XML.

Ruta: MyProject.Language / T4 / CreateAppLocalizationEN.tt

#@ template debug="false" hostspecific="true" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ assembly name="System.Windows.Forms" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.Resources" #>
<#@ import namespace="System.Collections" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.ComponentModel.Design" #>
<#@ output extension=".xml" #>
<#
var fileName = "../Resources/Resources.en.resx";
var fileResultName = "../T4/CreateAppLocalizationEN.xml";
var fileResultRexPath = Path.Combine(Path.GetDirectoryName(this.Host.ResolvePath("")), "MyProject.Language", fileName);
var fileResultPath = Path.Combine(Path.GetDirectoryName(this.Host.ResolvePath("")), "MyProject.Language", fileResultName);

    var fileNameDest = "strings.xml";

    var pathBaseDestination = Directory.GetParent(Directory.GetParent(this.Host.ResolvePath("")).ToString()).ToString();

    var currentPathDest =pathBaseDestination + "/MyProject.App.AndroidApp/Resources/values-en/" + fileNameDest;

    using(var reader = new ResXResourceReader(fileResultRexPath))
    {
        reader.UseResXDataNodes = true;
        #>
        <resources>
        <#

                foreach(DictionaryEntry entry in reader)
                {
                    var name = entry.Key;
                    //if(!name.ToString().Contains("WEBSHOP_") && !name.ToString().Contains("DASHBOARD_"))//only include keys with these prefixes, or the country ones.
                    //{
                    //  if(name.ToString().Length != 2)
                    //  {
                    //      continue;
                    //  }
                    //}
                    var node = (ResXDataNode)entry.Value;
                    var value = node.GetValue((ITypeResolutionService) null); 
                     if (!String.IsNullOrEmpty(value.ToString())) value = value.ToString().Replace("\n", "");
                     if (!String.IsNullOrEmpty(value.ToString())) value = value.ToString().Replace("\r", "");
                     if (!String.IsNullOrEmpty(value.ToString())) value = value.ToString().Replace("&", "&amp;");
                     if (!String.IsNullOrEmpty(value.ToString())) value = value.ToString().Replace("<<", "");
                     //if (!String.IsNullOrEmpty(value.ToString())) value = value.ToString().Replace("'", "\'");
#>
              <string name="<#=name#>">"<#=value#>"</string>
<#      
                }
#>
            <string name="WEBSHOP_LASTELEMENT">just ignore this</string>
<#
        #>
        </resources>
        <#
        File.Copy(fileResultPath, currentPathDest, true);
    }

#>

Android funciona con values-xxcarpetas, por lo que lo anterior es para inglés en la values-encarpeta. Pero también debe generar un valor predeterminado que vaya a la valuescarpeta. Simplemente copie la plantilla T4 y cambie la carpeta en el código anterior.

Ahí lo tienes, ahora puedes usar un solo archivo de recursos para todos tus proyectos. Esto hace que sea muy fácil exportar todo a un documento excl y dejar que alguien lo traduzca e importe nuevamente.

Un agradecimiento especial a esta increíble extensión VS que funciona de maravilla con resxarchivos. Considere donarle por su increíble trabajo (no tengo nada que ver con eso, me encanta la extensión).

CularBytes
fuente
1. ¿Cómo se agregan más idiomas después de la implementación ?, agregando más recursos a Mylanguage y recompilando y luego volviendo a implementar? (2) ¿Hay algún IDE o herramienta que haya utilizado para la traducción (tengo más de 40 formularios en winform), puede compartir? (3) Lo probé y no obtuve la traducción cuando cambié la cultura al árabe, crearé una pregunta y se lo haré saber
Smith
5
1: Simplemente duplique Resources.xx.resx y cambie xx y en todas partes donde tenga las declaraciones de cambio agregue el idioma. 2 Uso la extensión ResxManager (por TomEnglert), se puede instalar a través de Herramientas -> Extensiones, una buena manera de tener los idiomas uno al lado del otro, pero la traducción real la realiza otra persona (exportar e importar fácilmente a / desde Excel con ResxManager). 3. Encontrado esta última vez también al agregar uno también, verifique todos los archivos que se enumeran arriba, pero algunos puntos de interrupción. Sin embargo, no usé esto en WinForms.
CularBytes
13
¿Puedo votar a favor mi propia respuesta? Solo tuve que verificar estúpidamente mi propia respuesta para corregir un error para cambiar entre idiomas en WPF -.-
CularBytes
1
@TiagoBrenck Hola, solo en esta situación específica, si el inglés es su idioma predeterminado, puede crear un archivo resources.en-gb.resx y agregar los cambios del 1% allí. De forma predeterminada, si se selecciona el idioma en-gb y las palabras no se traducen, se usa el idioma predeterminado (resources.resx).
CularBytes
1
¿Cómo ha estructurado las claves del archivo de recursos? Ya que veo que solo usa un archivo de recursos y, según usted, tiene una aplicación enorme, ¿cómo ha dividido las claves? Algo como "Feature.MyMessage" o "Area.Feature.MyMessage"
Francesco Venturini
21

He visto proyectos implementados utilizando varios enfoques diferentes, cada uno tiene sus méritos e inconvenientes.

  • 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 era un fastidio saber qué mantener.
  • Uno usó archivos de recursos de la manera que usted sugiere 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 ha elegido tiene mucho sentido. También sería interesante ver las respuestas de otras personas, ya que a menudo me pregunto si hay una mejor manera de hacer cosas como esta. He visto numerosos recursos que apuntan al método de uso de recursos, incluido uno aquí en SO .

BenAlabaster
fuente
5

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

Las aplicaciones web pueden almacenar la información en la base de datos como han sugerido otros carteles, pero recomiendo usar archivos de recursos separados. Es decir archivos de recursos separada de su fuente . Los archivos de recursos separados reducen la contención por los mismos archivos y, a medida que su proyecto crezca, 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 usar ensamblados de recursos separados personalizados para cada configuración regional.

La capacidad de WPF para ajustar el tamaño de los elementos de la interfaz de usuario al 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, las herramientas de localización de WPF: msbuild, locbaml (y tal vez una hoja de cálculo de Excel) son tediosas de usar, pero funcionan.

Algo solo ligeramente relacionado: un problema común al que me enfrento es la integración de sistemas heredados que envían mensajes de error (generalmente en inglés), no códigos de error. Esto obliga a realizar cambios en los sistemas heredados o asignar cadenas de backend a mis propios códigos de error y luego a cadenas localizadas ... Los códigos de error son amigos de las localizaciones

MW_dev
fuente
4

+1 Base de datos

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

Usamos un sistema en el que todos los controles se asignaban en un archivo XML (uno por formulario) a los ID de recursos de idioma, pero todos los ID estaban en la base de datos.

Básicamente, en lugar de que cada control contenga el ID (implementando una interfaz o usando la propiedad de la etiqueta en VB6), usamos el hecho de que en .NET, el árbol de control era fácilmente detectable mediante la reflexión. Un proceso en el que el formulario cargado generaría el archivo XML si faltaba. El archivo XML asignaría los controles a sus ID de recursos, por lo que simplemente era necesario completarlo y asignarlo a la base de datos. Esto significaba que no había necesidad de cambiar el binario compilado si algo no estaba etiquetado, o si era necesario dividirlo en otra ID (algunas palabras en inglés que podrían usarse como sustantivos y verbos podrían necesitar traducirse a dos palabras diferentes en el diccionario y no se puede volver a utilizar, pero es posible que no lo descubra durante la asignación inicial de ID).

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

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

Cade Roux
fuente
Me gusta su método, ¿puede decirme cómo se genera el archivo xml y luego se asigna a la base de datos?
Smith
En Form_Load o lo que sea, se invocó la función de traducción en la instancia del formulario. Se cargó el archivo XML para ese formulario. Si no existía, fue creado. No tengo el esquema a mano, pero básicamente, asignó el nombre de control en un formulario a una ID de traducción. Por tanto, cualquier control del formulario que no estuviera en el archivo XML obtendría una entrada sin ID de traducción. Debido a que se crearían a pedido, simplemente podría crear su formulario, ejecutar la aplicación que compilaría o actualizaría el archivo XML para los controles faltantes. Luego, complete los ID de traducción de los elementos.
Cade Roux
4

He estado buscando y he encontrado esto:

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

Es de código abierto Es GRATIS (y seguirá siendo gratuito) está en un estado real

En una aplicación de Windows, puede 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 web el enfoque podría ser el mismo.

¡Buena suerte!

JxXx
fuente
2

Yo iría con los archivos de recursos múltiples. 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 idioma global junto con los archivos de recursos del idioma de formulario.

Localización en Visual Studio 2008

Consideraría que es el mejor enfoque al menos para el desarrollo de WinForm.

KMessenger
fuente
Un inconveniente de los recursos es que debe reiniciar para cambiar de idioma. Probablemente sea aceptable para la mayoría, pero es lo que más me molesta ...
Roman Starkov
2

Puede utilizar herramientas comerciales como Sisulizer . Creará un ensamblaje satélite para cada idioma. Lo único que debe prestar atención es no ofuscar los nombres de las clases de formularios (si usa ofuscator).

Davorin
fuente
0

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

Vasil
fuente
0

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

Cossintan
fuente
0

Los archivos de recursos estándar son más fáciles. Sin embargo, si tiene datos que dependen 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

Ben Dempsey
fuente