C#: resurse localizate și texte fără concatenări fragile
Organizează textele unei aplicații C# pentru schimbarea limbii. Folosește chei, formatare și o regulă de fallback înainte de integrarea cu fișiere resx.
În acest material
Textele scrise direct în zeci de handleri sunt greu de corectat sau tradus. Separăm cheia mesajului de valoarea afișată. Începem cu un dicționar mic pentru a înțelege mecanismul, apoi îl poți muta în resurse .resx gestionate de Visual Studio. Schimbarea limbii nu trebuie să schimbe ID-urile sau regulile aplicației.
Cum lucrezi cu exemplul
Programul complet folosește C# 7.3 și API-uri disponibile în .NET Framework 4.8. Deschide Lesson.csproj din arhivă sau creează un proiect Console App (.NET Framework 4.8) și înlocuiește Program.cs. Datele de demonstrație sunt incluse în cod.
Descarcă sursele și instrucțiunile.
Ideea și pașii de implementare
Fiecare limbă are aceleași chei: title, save și count. Mesajul count conține un parametru {0}, completat prin string.Format. Alegerea limbii este o valoare separată. Funcția TextFor caută în limba activă și revine la română dacă lipsește cheia; lipsa și în română este o eroare explicită.
Într-un proiect cu resx, ResourceManager și CurrentUICulture oferă mecanisme pentru selecția resurselor. CurrentCulture influențează formatarea numerelor și datelor, în timp ce CurrentUICulture este folosită pentru alegerea textelor interfeței. Nu le considera identice ca responsabilitate.
Exemplu și rezultat așteptat
În română, cheia save produce Salveaza, iar count cu valoarea 3 produce Carti: 3. În engleză obții Save și Books: 3. Același număr și aceeași cheie de domeniu sunt folosite în ambele cazuri; doar prezentarea diferă.
Cheie: count → Limba: ro / en → Parametru: 3 → Carti: 3 / Books: 3.Mărește schema ↗
Codul complet
using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Globalization;
using System.Xml.Linq;
using System.Data;
class Program {
static readonly Dictionary<string,string> ro=new Dictionary<string,string> {
{"save","Salveaza"},{"count","Carti: {0}"},{"title","Biblioteca"}};
static readonly Dictionary<string,string> en=new Dictionary<string,string> {
{"save","Save"},{"count","Books: {0}"},{"title","Library"}};
static string TextFor(string language,string key) {
string value; var selected=language=="en" ? en : ro;
if(selected.TryGetValue(key,out value) || ro.TryGetValue(key,out value))return value;
throw new KeyNotFoundException(key);
}
static void Main() {
foreach(string language in new[] {"ro","en"}) {
Console.WriteLine(TextFor(language,"save"));
Console.WriteLine(string.Format(CultureInfo.InvariantCulture,TextFor(language,"count"),3));
}
}
}
Rezultatul programului:
Salveaza
Carti: 3
Save
Books: 3
Greșeli și limite
Nu construi propoziții prin concatenarea multor bucăți traduse independent: ordinea cuvintelor poate varia. Nu folosi textul butonului pentru a decide ce comandă execută. Nu presupune că textul tradus are aceeași lungime; verifică layout-ul cu valori mai lungi și cu diacritice.
Exersează
Adaugă cheia cancel în română, dar nu în engleză, și verifică fallback-ul. Adaugă apoi traducerea și confirmă schimbarea. Mută cheile într-un fișier Resources.resx și într-un Resources.en.resx într-un proiect de probă. Verifică ecranul la ambele limbi fără să schimbi datele salvate.
Continuă parcursul
Parcursul complet de 50 de lecții
Lecția precedentă: C#: rapoarte tipărite și paginare cu PrintDocument
Lecția următoare: C#: Undo și Redo pentru modificări controlate.
Referință: documentația Microsoft.
Întrebări frecvente
Textul tradus poate fi folosit drept ID?
Nu. Folosește chei stabile și păstrează textul numai pentru prezentare.
CurrentCulture și CurrentUICulture sunt același lucru?
Au roluri diferite: formatarea valorilor, respectiv selectarea resurselor interfeței.
De ce am nevoie de fallback?
Pentru un comportament previzibil când o traducere lipsește, fără text gol ascuns.
Un pas mai departe
Autentifică-te pentru a păstra progresul în cont.