Il modo migliore per implementare multi-lingua / globalizzazione in un grande progetto .NET


87

Presto lavorerò a un grande progetto c # e vorrei creare il supporto multilingue sin dall'inizio. Ho provato a farlo funzionare utilizzando un file di risorse separato per ogni lingua, quindi utilizzare un gestore di risorse per caricare le stringhe.

Ci sono altri buoni approcci che potrei esaminare?

Risposte:


91

Usa un progetto separato con Risorse

Posso dirlo dalla nostra esperienza, avendo una soluzione attuale con 12 24 progetti che include API, MVC, librerie di progetti (funzionalità di base), WPF, UWP e Xamarin. Vale la pena leggere questo lungo post perché penso che sia il modo migliore per farlo. Con l'aiuto di strumenti VS facilmente esportabili e importabili da inviare ad agenzie di traduzione o revisione da altre persone.

EDIT 02/2018: ancora forte, convertirlo in una libreria .NET Standard rende possibile persino usarlo su .NET Framework e NET Core. Ho aggiunto una sezione extra per convertirlo in JSON in modo che ad esempio angular possa usarlo.

EDIT 2019: andando avanti con Xamarin, funziona ancora su tutte le piattaforme. Ad esempio, Xamarin.Forms consiglia di utilizzare anche i file resx. (Non ho ancora sviluppato un'app in Xamarin.Forms, ma la documentazione, che è molto dettagliata per iniziare, la copre: Xamarin.Forms Documentation ). Proprio come convertirlo in JSON, possiamo anche convertirlo in un file .xml per Xamarin.Android.

EDIT 2019 (2): durante l'aggiornamento a UWP da WPF, ho riscontrato che in UWP preferiscono utilizzare un altro tipo di file .resw, che è identico in termini di contenuto ma l'utilizzo è diverso. Ho trovato un modo diverso di farlo che, a mio parere, funziona meglio della soluzione predefinita .

EDIT 2020: aggiornati alcuni suggerimenti per progetti più grandi (modulair) che potrebbero richiedere progetti in più lingue.

Quindi, arriviamo a questo.

Professionisti

  • Fortemente digitato quasi ovunque.
  • In WPF non devi occuparti di ResourceDirectories.
  • Supportato per ASP.NET, librerie di classi, WPF, Xamarin, .NET Core, .NET Standard per quanto ho testato.
  • Non sono necessarie librerie di terze parti aggiuntive.
  • Supporta il fallback della cultura: en-US -> en.
  • Non solo back-end, funziona anche in XAML per WPF e Xamarin.Forms, in .cshtml per MVC.
  • Gestisci facilmente la lingua cambiando il file Thread.CurrentThread.CurrentCulture
  • I motori di ricerca possono eseguire la scansione in diverse lingue e l'utente può inviare o salvare URL specifici della lingua.

Contro

  • WPF XAML a volte presenta bug, le stringhe appena aggiunte non vengono visualizzate direttamente. Ricostruire è la correzione temporanea (vs2015).
  • UWP XAML non mostra suggerimenti intellisense e non mostra il testo durante la progettazione.
  • Dimmi.

Impostare

Crea un progetto linguistico nella tua soluzione, dagli un nome come MyProject.Language . Aggiungi una cartella chiamata Risorse e in quella cartella crea due file Risorse (.resx). Uno chiamato Resources.resx e un altro chiamato Resources.en.resx (o .en-GB.resx per specifico). Nella mia implementazione, ho la lingua NL (olandese) come lingua predefinita, quindi quella va nel mio primo file e l'inglese va nel mio secondo file.

L'installazione dovrebbe essere simile a questa:

progetto di impostazione della lingua

Le proprietà per Resources.resx devono essere: proprietà

Assicurati che lo spazio dei nomi dello strumento personalizzato sia impostato sullo spazio dei nomi del progetto. Il motivo è che in WPF non è possibile fare riferimento a ResourcesXAML all'interno.

E all'interno del file di risorse, imposta il modificatore di accesso su Pubblico:

modificatore di accesso

Se hai un'applicazione così grande (diciamo moduli diversi) puoi considerare di creare più progetti come sopra. In tal caso potresti anteporre alle chiavi e alle classi di risorse il modulo specifico. Usa il miglior editor di lingue disponibile per Visual Studio per combinare tutti i file in un'unica panoramica.

Utilizzo in un altro progetto

Riferimento al progetto: fare clic con il pulsante destro del mouse su Riferimenti -> Aggiungi riferimento -> Prjects \ Solutions.

Usa lo spazio dei nomi in un file: using MyProject.Language;

Usalo in questo modo nel back-end: string someText = Resources.orderGeneralError; se c'è qualcos'altro chiamato Risorse, inserisci l'intero spazio dei nomi.

Utilizzo in MVC

In MVC puoi fare come preferisci impostare la lingua, ma ho usato URL parametrizzati, che possono essere impostati in questo modo:

RouteConfig.cs Sotto le altre mappature

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 (potrebbe essere necessario aggiungere, in tal caso, aggiungere FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);al Application_start()metodo inGlobal.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 imposta solo le informazioni sulla 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)
    {

    }
}

Utilizzo in .cshtml

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

oppure, se non vuoi definire gli utilizzi, riempi l'intero spazio dei nomi OPPURE puoi definire lo spazio dei nomi in /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>

Questo tutorial sull'implementazione di mvc: blog tutorial impressionante

Utilizzo di librerie di classi per i modelli

L'utilizzo del back-end è lo stesso, ma è solo un esempio per l'utilizzo negli attributi

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

Se hai reshaper, controllerà automaticamente se il nome della risorsa specificato esiste. Se si preferisce l'indipendenza dai tipi, è possibile utilizzare i modelli T4 per generare un'enumerazione

Utilizzo in WPF.

Ovviamente aggiungi un riferimento al tuo MyProject.Language spazio dei nomi , sappiamo come usarlo nel back-end.

In XAML, all'interno dell'intestazione di una finestra o di un controllo utente, aggiungi un riferimento allo spazio dei nomi chiamato in questo langmodo:

<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">

Quindi, all'interno di un'etichetta:

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

Poiché è fortemente tipizzato, sei sicuro che la stringa della risorsa esista. Potrebbe essere necessario ricompilare il progetto a volte durante l'installazione, WPF a volte è bacato con nuovi spazi dei nomi.

Un'altra cosa per WPF, imposta la lingua all'interno del file App.xaml.cs. Puoi eseguire la tua implementazione (scegli durante l'installazione) o lasciare che sia il sistema a decidere.

Utilizzo in UWP

In UWP, Microsoft utilizza questa soluzione , il che significa che dovrai creare nuovi file di risorse. Inoltre non puoi riutilizzare il testo perché vogliono che tu imposti il x:Uidcontrollo in XAML su una chiave nelle tue risorse. E nelle tue risorse devi fare Example.Textper riempire un fileTextBlock testo. Non mi è piaciuta affatto quella soluzione perché voglio riutilizzare i miei file di risorse. Alla fine ho trovato la seguente soluzione. L'ho appena scoperto oggi (2019-09-26), quindi potrei tornare con qualcos'altro se si scopre che non funziona come desiderato.

Aggiungi questo al tuo progetto:

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

Aggiungi questo a App.xaml.csnel costruttore:

CustomXamlResourceLoader.Current = new MyXamlResourceLoader();

Ovunque tu voglia nella tua app, usa questo per cambiare la lingua:

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

L'ultima riga è necessaria per aggiornare l'interfaccia utente. Mentre sto ancora lavorando a questo progetto ho notato che dovevo farlo 2 volte. Potrei finire con una selezione della lingua la prima volta che l'utente inizia. Ma poiché questo sarà distribuito tramite Windows Store, la lingua è solitamente uguale alla lingua di sistema.

Quindi usa in XAML:

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

Usandolo in Angular (converti in JSON)

Oggigiorno è più comune avere un framework come Angular in combinazione con i componenti, quindi senza cshtml. Le traduzioni sono memorizzate in file json, non ho intenzione di spiegare come funziona, consiglio vivamente ngx-translate invece della multi-traduzione angolare. Quindi, se vuoi convertire le traduzioni in un file JSON, è abbastanza semplice, utilizzo uno script modello T4 che converte il file delle risorse in un file json. Consiglio di installare l' editor T4 per leggere la sintassi e usarlo correttamente perché è necessario apportare alcune modifiche.

Solo una cosa da notare: non è possibile generare i dati, copiarli, pulire i dati e generarli per un'altra lingua. Quindi devi copiare il codice di seguito tante volte quante sono le lingue che hai e cambiare la voce prima di "// scegli la lingua qui". Al momento non c'è tempo per risolvere questo problema, ma probabilmente aggiornerà in seguito (se interessato).

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


#>

Se hai un'applicazione modulair e hai seguito il mio suggerimento per creare progetti in più lingue, dovrai creare un file T4 per ciascuno di essi. Assicurati che i file json siano definiti logicamente, non è necessario che lo sia en.json, può anche essere example-en.json. Per combinare più file json da utilizzare con ngx-translate , segui le istruzioni qui

Usa in Xamarin.Android

Come spiegato sopra negli aggiornamenti, utilizzo lo stesso metodo che ho fatto con Angular / JSON. Ma Android utilizza file XML, quindi ho scritto un file T4 che genera quei file XML.

Percorso: 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 funziona con le values-xxcartelle, quindi sopra è per l'inglese nella values-encartella. Ma devi anche generare un valore predefinito che va nella valuescartella. Basta copiare sopra il modello T4 e cambiare la cartella nel codice sopra.

Ecco fatto, ora puoi utilizzare un unico file di risorse per tutti i tuoi progetti. Ciò semplifica l'esportazione di tutto in un documento escl e consente a qualcuno di tradurlo e importarlo di nuovo.

Un ringraziamento speciale a questa straordinaria estensione VS che funziona alla grande con i resxfile. Considerare donando a lui per il suo lavoro impressionante (non ho nulla a che fare con questo, ho solo l'amore l'estensione).


1. come si aggiungono più lingue dopo la distribuzione ?, aggiungendo più risorse a Mylanguage, ricompilando e quindi ridistribuendo? (2) C'è qualche IDE o strumento che hai usato per la traduzione (ho oltre 40 moduli in winform), puoi condividere? (3) L'ho provato e non ha ottenuto la traduzione quando ho cambiato la cultura in arabo, creerò una domanda e ti farò sapere
Smith

5
1: Basta pubblicare Resources.xx.resx e modificare xx e ovunque si trovino le istruzioni switch aggiungere la lingua. 2 Uso l'estensione ResxManager (di TomEnglert), può essere installata tramite Strumenti -> Estensioni, un bel modo per avere le lingue una accanto all'altra ma la traduzione effettiva è fatta da qualcun altro (facile esportazione e importazione da / a Excel con ResxManager). 3. Incontrato anche quest'ultima volta aggiungendone uno, controlla tutti i file elencati sopra, ma alcuni punti di interruzione. Tuttavia, non l'ho usato in WinForms.
CularBytes

13
Posso dare un voto positivo alla mia risposta? Ho dovuto solo controllare stupidamente la mia risposta per correggere un bug per il passaggio da una lingua
all'altra

1
@TiagoBrenck Ciao, solo in questa situazione specifica, se l'inglese è la tua lingua predefinita, potresti creare un file resources.en-gb.resx e aggiungere le modifiche dell'1% lì. Per impostazione predefinita, se è selezionata la lingua en-gb e le parole non vengono tradotte, utilizza la lingua predefinita (resources.resx).
CularBytes

1
Come hai strutturato le chiavi del Resource file? Dato che vedo che usi solo un file di risorse e, secondo te, hai un'app enorme, come hai diviso le chiavi? Qualcosa come "Feature.MyMessage", o "Area.Feature.MyMessage"
Francesco Venturini

21

Ho visto progetti implementati utilizzando una serie di approcci diversi, ognuno con i suoi pregi e difetti.

  • Uno lo ha fatto nel file di configurazione (non il mio preferito)
  • Uno lo ha fatto utilizzando un database: ha funzionato abbastanza bene, ma è stato un problema per sapere cosa mantenere.
  • Uno ha utilizzato i file di risorse nel modo in cui suggerisci e devo dire che era il mio approccio preferito.
  • Il più semplice lo ha fatto usando un file include pieno di stringhe - brutto.

Direi che il metodo delle risorse che hai scelto ha molto senso. Sarebbe interessante vedere anche le risposte di altre persone perché spesso mi chiedo se ci sia un modo migliore per fare cose del genere. Ho visto numerose risorse che puntano tutte al metodo di utilizzo delle risorse, inclusa una qui su SO .


5

Non credo che ci sia un "modo migliore". Dipenderà davvero dalle tecnologie e dal tipo di applicazione che stai creando.

Le webapp possono memorizzare le informazioni nel database come suggerito da altri poster, ma io consiglio di usare file di risorse separati. Cioè file di risorse separati dalla tua fonte . File di risorse separati riduce la contesa per gli stessi file e man mano che il progetto cresce, potresti scoprire che la localizzazione verrà eseguita separatamente dalla logica aziendale. (Programmatori e traduttori).

I guru di Microsoft WinForm e WPF consigliano di utilizzare assembly di risorse separati personalizzati per ogni locale.

La capacità di WPF di dimensionare gli elementi dell'interfaccia utente in base al contenuto riduce il lavoro di layout richiesto, ad esempio: (le parole giapponesi sono molto più brevi dell'inglese).

Se stai prendendo in considerazione WPF: ti suggerisco di leggere questo articolo di msdn Per essere sincero ho trovato gli strumenti di localizzazione di WPF: msbuild, locbaml, (e forse un foglio di calcolo Excel) noiosi da usare, ma funziona.

Qualcosa solo leggermente correlato: un problema comune che affronto è l'integrazione di sistemi legacy che inviano messaggi di errore (di solito in inglese), non codici di errore. Ciò forza le modifiche ai sistemi legacy o la mappatura delle stringhe di backend ai miei codici di errore e quindi alle stringhe localizzate ... yech. I codici di errore sono amici delle localizzazioni


4

+1 database

I moduli nella tua app possono anche tradursi nuovamente da soli al volo se vengono apportate correzioni al database.

Abbiamo utilizzato un sistema in cui tutti i controlli erano mappati in un file XML (uno per modulo) agli ID delle risorse della lingua, ma tutti gli ID erano nel database.

Fondamentalmente, invece di avere ogni controllo in possesso dell'ID (implementando un'interfaccia o utilizzando la proprietà tag in VB6), abbiamo utilizzato il fatto che in .NET l'albero dei controlli era facilmente individuabile attraverso la riflessione. Un processo quando il modulo viene caricato creerà il file XML se manca. Il file XML associava i controlli ai loro ID risorsa, quindi questo doveva semplicemente essere compilato e mappato al database. Ciò significava che non c'era bisogno di cambiare il binario compilato se qualcosa non era etichettato o se doveva essere diviso in un altro ID (alcune parole in inglese che potrebbero essere usate sia come sostantivi che come verbi potrebbero dover essere tradotte in due parole diverse nel dizionario e non essere riutilizzato, ma potresti non scoprirlo durante l'assegnazione iniziale degli ID).

Gli unici in cui l'app viene coinvolta di più è quando viene utilizzata una fase con punti di inserimento.

Il software di traduzione del database era la tua schermata di manutenzione CRUD di base con varie opzioni di flusso di lavoro per facilitare l'esame delle traduzioni mancanti, ecc.


Mi piace il tuo metodo, puoi dirmi come viene generato il file xml e poi mappato nel database?
Smith

In Form_Load o qualsiasi altra cosa, la funzione di traduzione è stata richiamata sull'istanza del form. Il file XML per quel modulo è stato caricato. Se non esisteva è stato creato. Non ho lo schema a portata di mano, ma fondamentalmente ha mappato il nome del controllo su un modulo a un ID di traduzione. Pertanto, qualsiasi controllo sul modulo che non fosse nel file XML otterrebbe una voce senza ID di traduzione. Poiché verrebbero creati su richiesta, potresti semplicemente creare il tuo modulo, eseguire l'app che creerà o aggiornerà il file XML per eventuali controlli mancanti. Quindi inserisci gli ID di traduzione per gli articoli.
Cade Roux

4

Ho cercato e ho trovato questo:

Se stai usando WPF o Silverlight, il tuo approccio potrebbe essere usare WPF LocalizationExtension per molti motivi.

È Open Source È GRATUITO (e rimarrà gratuito) è in uno stato reale

In un'applicazione Windows potresti fare qualcosa del genere:

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

E penso che su una pagina Wep l'approccio potrebbe essere lo stesso.

In bocca al lupo!


2

Vorrei utilizzare più file di risorse. Non dovrebbe essere così difficile da configurare. In effetti, di recente ho risposto a una domanda simile sull'impostazione di file di risorse basati sulla lingua globale insieme ai file di risorse della lingua del modulo.

Localizzazione in Visual Studio 2008

Lo considero l'approccio migliore almeno per lo sviluppo di WinForm.


Uno svantaggio delle risorse è che devi riavviare per cambiare lingua. Probabilmente è accettabile per la maggior parte, ma è il mio cruccio ...
Roman Starkov

2

Puoi usare strumenti commerciali come Sisulizer . Creerà un assembly satellite per ogni lingua. L'unica cosa a cui dovresti prestare attenzione è non offuscare i nomi delle classi dei form (se usi l'offuscatore).


0

La maggior parte dei progetti opensource utilizza GetText per questo scopo. Non so come e se sia mai stato utilizzato in un progetto .Net prima.


0

Utilizziamo un provider personalizzato per il supporto multilingue e inseriamo tutti i testi in una tabella di database. Funziona bene tranne che a volte affrontiamo problemi di memorizzazione nella cache durante l'aggiornamento dei testi nel database senza aggiornare l'applicazione web.


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.