Jak korzystać z lokalizacji w C #

268

Po prostu nie mogę uruchomić lokalizacji.

Mam bibliotekę klas. Teraz chcę tam utworzyć pliki resx i zwrócić niektóre wartości oparte na kulturze wątków.

Jak mogę to zrobić?

J L.
źródło
PS: upewnij się, że zainstalowałeś bezpłatne rozszerzenie Microsoft MAT (Multilingual App Toolkit) dla studia wizualnego ;-)
juFo

Odpowiedzi:

571
  • Dodaj plik zasobów do swojego projektu (możesz go nazwać „strings.resx”), wykonując następujące czynności:
    Kliknij prawym przyciskiem myszy Właściwości w projekcie, wybierz Dodaj -> Nowy element ... w menu kontekstowym, a następnie na liście Elementy Visual C # wybierają „Plik zasobów” i nadają mu nazwę strings.resx.
  • Dodaj ciąg znaków resouce do pliku resx i nadaj mu dobrą nazwę (przykład: nazwij go „Hello” i nadaj mu wartość „Hello”)
  • Zapisz plik zasobów ( uwaga: będzie to domyślny plik zasobów, ponieważ nie ma dwuliterowego kodu języka)
  • Dodaj odniesienia do swojego programu: System.ThreadingiSystem.Globalization

Uruchom ten kod:

Console.WriteLine(Properties.strings.Hello);

Powinien wypisać „Cześć”.

Teraz dodaj nowy plik zasobów o nazwie „strings.fr.resx” (zwróć uwagę na część „fr”; ta będzie zawierać zasoby w języku francuskim). Dodaj zasób łańcucha o takiej samej nazwie jak w strings.resx, ale o wartości w języku francuskim (Name = „Hello”, Value = „Salut”). Teraz, jeśli uruchomisz następujący kod, powinien wypisać Salut:

Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("fr-FR");
Console.WriteLine(Properties.strings.Hello);

Co się dzieje, system szuka zasobu dla „fr-FR”. Nie znajdzie żadnego (ponieważ w pliku określono „fr”). Następnie wróci do sprawdzania „fr”, które znajdzie (i używa).

Poniższy kod wyświetli „Hello”:

Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("en-US");
Console.WriteLine(Properties.strings.Hello);

Wynika to z tego, że nie znajduje żadnego zasobu „en-US”, a także zasobu „en”, więc powróci do domyślnego, czyli tego, który dodaliśmy od samego początku.

W razie potrzeby możesz tworzyć pliki z bardziej szczegółowymi zasobami (na przykład strings.fr-FR.resx i strings.fr-CA.resx odpowiednio dla francuskiego we Francji i Kanadzie). W każdym takim pliku musisz dodać zasoby dla tych ciągów, które różnią się od zasobu, do którego by się wycofał. Więc jeśli tekst jest taki sam we Francji i Kanadzie, możesz umieścić go w strings.fr.resx, podczas gdy łańcuchy, które różnią się w kanadyjskim francuskim, mogą przejść do strings.fr-CA.resx.

Fredrik Mörk
źródło
24
Odpowiedź może odnosić się do hydrauliki „za kulisami” wykonywanej przez Visual Studio tutaj: plik resx.designer.cs, dzięki czemu intellisense działa; zestawy satelitarne skompilowane z biblioteką klas, które należy wdrożyć wraz ze skompilowanym zestawem i wszelkimi późniejszymi projektami, które go wykorzystują itp. Odpowiedź jest miła i prosta, ale nie pomaga wyjaśnić, co może się nie powieść, np. jeśli nie korzystasz z Visual Studio.
Tao
13
+1 post! Zamiast tworzyć pliki ręcznie, wypróbuj Zeta Resource Editor ( zeta-resource-editor.com/index.html ). Jest bezpłatny i pomaga wykonywać tego rodzaju tłumaczenia DUŻO szybciej niż tylko w VS.
Killnine,
4
Access Modifiernależy ustawić Publicdla generowania klasy zasobów. Klasa niekoniecznie musi znajdować się w przestrzeni nazw Właściwości, tam umieszcza się plik .resx.
Andrey Moiseev
3
Należy pamiętać, że w VS 2017 resx z lokalizacją w winform nie działa z powodu błędu (przynajmniej do wersji 15.4). Bilet jest dostępny: developercommunity.visualstudio.com/content/problem/63772/…
muccix
4
Począwszy od platformy .NET 4.5 można również używać System.Globalization.CultureInfo.DefaultThreadCurrentCulture zamiast Thread.CurrentThread.CurrentUICulture, aby zmienić ustawienia regionalne dla całej aplikacji zamiast wątku po wątku
GrixM
41

Właściwie to całkiem proste. Utwórz na przykład nowy plik zasobów Strings.resx. Ustaw Access Modifierna Public. Użyj odpowiedniego szablonu pliku, aby Visual Studio automatycznie wygenerował klasę akcesorium ( Stringsw tym przypadku będzie to nazwa ). To jest twój domyślny język.

Teraz, jeśli chcesz dodać, powiedzmy, niemiecką lokalizację, dodaj zlokalizowany plik resx. Zazwyczaj tak będzie Strings.de.resxw tym przypadku. Jeśli chcesz dodać dodatkową lokalizację, powiedzmy w Austrii, dodatkowo utworzysz Strings.de-AT.resx.

Teraz stwórz ciąg - powiedzmy ciąg z nazwą HelloWorld. W swoim Strings.resxdodaj ten ciąg o wartości „Witaj, świecie!”. W Strings.de.resxdodaj „Cześć, Welt!”. I Strings.de-AT.resxdodaj „Servus, Welt!”. To wszystko na razie.

Teraz masz wygenerowaną Stringsklasę i ma ona właściwość z geterem HelloWorld. Uzyskanie tej właściwości spowoduje załadowanie „Servus, Welt!” gdy twoje ustawienia regionalne to de-AT, „Cześć, Welt!”, gdy twoje ustawienia regionalne to dowolne inne ustawienia regionalne (w tym de-DE i de-CH) oraz „Hello, World!”, gdy twoje ustawienia regionalne są czymś innym. Jeśli ciąg znaków jest brak w zlokalizowanej wersji, menedżer zasobów automatycznie przejdzie przez łańcuch, od najbardziej wyspecjalizowanego do niezmiennego zasobu.

Możesz użyć tej ResourceManagerklasy, aby uzyskać większą kontrolę nad tym, jak dokładnie ładujesz rzeczy. Generowana Stringsklasa również z niej korzysta.

OregonGhost
źródło
jak ustawić ustawienia regionalne?
Matheus Simon
1
@MatheusSimon: Nie musisz. Domyślnie używane są bieżące ustawienia narodowe użytkownika. Jeśli chcesz wymusić określone ustawienia narodowe (np. W celu umożliwienia użytkownikom ręcznej zmiany języka), musisz ustawić System.Threading.Thread.CurrentCulture i CurrentUICulture w każdym wątku , prawdopodobnie przed załadowaniem jakichkolwiek zasobów po raz pierwszy. Łatwiej jest zrestartować aplikację w tym celu niż aktualizować w czasie wykonywania.
OregonGhost,
15

Ponadto świetna odpowiedź @Fredrik Mörk na ciągi znaków, aby dodać lokalizację do formularza, wykonaj następujące czynności:

  • Ustaw forma własności „s "Localizable"dotrue
  • Zmień właściwość formularza na Languageżądany język (z miłego menu rozwijanego z wszystkimi nimi)
  • Przetłumacz elementy sterujące w tej formie i przesuwaj je w razie potrzeby (zmiażdż te naprawdę długie pełne francuskie zdania!)

Edycja: ten artykuł MSDN na temat lokalizowania formularzy Windows nie jest oryginalnym, który połączyłem ... ale w razie potrzeby może rzucić więcej światła. (stary został zabrany)

noelicus
źródło
Artykuł msdn nie jest już dostępny, jakiś zamiennik?
fuomag9
Nie jestem pewien - połączyłem najlepszy, jaki mogłem zobaczyć, ale nie pamiętam, jak ten artykuł był 7 lat temu;)
noelicus
14

Świetna odpowiedź F.Mörk. Ale jeśli chcesz zaktualizować tłumaczenie lub dodać nowe języki po wydaniu aplikacji, utkniesz, ponieważ zawsze musisz ją ponownie skompilować, aby wygenerować zasoby.dll.

Oto rozwiązanie, aby ręcznie skompilować bibliotekę zasobów. Wykorzystuje narzędzia resgen.exe i al.exe (zainstalowane z SDK).

Załóżmy, że masz plik zasobów Strings.fr.resx, możesz skompilować dll zasobów z następującą partią:

resgen.exe /compile Strings.fr.resx,WpfRibbonApplication1.Strings.fr.resources 
Al.exe /t:lib /embed:WpfRibbonApplication1.Strings.fr.resources /culture:"fr" /out:"WpfRibbonApplication1.resources.dll"
del WpfRibbonApplication1.Strings.fr.resources
pause

Pamiętaj, aby zachować oryginalną przestrzeń nazw w nazwach plików (tutaj „WpfRibbonApplication1”)

Eric Bole-Feysot
źródło
2
Dziękujemy za komentarz dotyczący zachowania przestrzeni nazw (y), która - jeśli zostanie pominięta - nie wygeneruje żadnych błędów, ale po prostu powróci do rezerwowego zasobu.
Mosca Pt
11

Poprawka i opracowanie odpowiedzi @Fredrik Mörk .

  • Dodaj strings.resxplik zasobów do swojego projektu (lub inną nazwę pliku)
  • Ustaw Access Modifierna Public(w strings.resxzakładce otwartego pliku)
  • Dodaj ciąg zasobu do pliku resx: (przykład: nazwa Hello, wartość Hello)
  • Zapisz plik zasobów

Program Visual Studio automatycznie generuje odpowiednią stringsklasę, która jest faktycznie umieszczana strings.Designer.cs. Klasa znajduje się w tej samej przestrzeni nazw, w której można oczekiwać umieszczenia nowo utworzonego .cspliku.

Ten kod zawsze jest drukowany Hello, ponieważ jest to domyślny zasób i nie są dostępne zasoby specyficzne dla języka:

Console.WriteLine(strings.Hello);

Teraz dodaj nowy zasób specyficzny dla języka:

  • Dodaj strings.fr.resx(dla francuskiego)
  • Dodaj ciąg o takiej samej nazwie jak poprzednio, ale o innej wartości: (nazwa Hello, wartość Salut)

Drukuje się następujący kod Salut:

Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("fr-FR");
Console.WriteLine(strings.Hello);

Z jakiego zasobu korzysta się, zależy Thread.CurrentThread.CurrentUICulture. Ustawia się go w zależności od ustawień języka interfejsu użytkownika systemu Windows lub można ustawić ręcznie, jak w tym przykładzie. Dowiedz się więcej o tym tutaj .

Możesz dodać zasoby specyficzne dla kraju, takie jak strings.fr-FR.resxlub strings.fr-CA.resx.

Ciąg, który ma zostać użyty, jest ustalany w następującej kolejności:

  • Z zasobów krajowych, takich jak strings.fr-CA.resx
  • Z zasobów specyficznych dla języka, takich jak strings.fr.resx
  • Domyślnie strings.resx

Pamiętaj, że zasoby specyficzne dla języka generują zespoły satelitarne .

Dowiedz się również, czym się CurrentCultureróżni od CurrentUICulture tego .

Andrey Moiseev
źródło
1

W moim przypadku

[assembly: System.Resources.NeutralResourcesLanguage("ru-RU")]

w AssemblyInfo.cs uniemożliwił normalne działanie.

Aleksandr
źródło
0

Oprócz odpowiedzi @Eric Bole-Feysot :

Dzięki zespołom satelitarnym można tworzyć lokalizację na podstawie plików .dll / .exe . Tą drogą:

  • kod źródłowy (projekt VS) można oddzielić od projektu językowego,
  • dodanie nowego języka nie wymaga ponownej kompilacji projektu,
  • tłumaczenie może być wykonane nawet przez użytkownika końcowego.

Istnieje mało znane narzędzie o nazwie LSACreator (bezpłatne do niekomercyjnego użytku lub opcji zakupu), które umożliwia tworzenie lokalizacji na podstawie plików .dll / .exe. W rzeczywistości wewnętrznie (w katalogu projektu językowego) tworzy / zarządza zlokalizowanymi wersjami plików resx i kompiluje zespół w podobny sposób, jak opisał @Eric Bole-Feysot .

Tomasz Malik
źródło
0

ResourceManager i .resx są nieco niechlujne.

Możesz użyć Lexical.Localization ¹, który pozwala na osadzenie wartości domyślnych i wartości specyficznych dla kultury w kodzie, i może zostać rozszerzony w zewnętrznych plikach lokalizacyjnych dla późniejszych kultur (takich jak .json lub .resx).

public class MyClass
{
    /// <summary>
    /// Localization root for this class.
    /// </summary>
    static ILine localization = LineRoot.Global.Type<MyClass>();

    /// <summary>
    /// Localization key "Ok" with a default string, and couple of inlined strings for two cultures.
    /// </summary>
    static ILine ok = localization.Key("Success")
            .Text("Success")
            .fi("Onnistui")
            .sv("Det funkar");

    /// <summary>
    /// Localization key "Error" with a default string, and couple of inlined ones for two cultures.
    /// </summary>
    static ILine error = localization.Key("Error")
            .Format("Error (Code=0x{0:X8})")
            .fi("Virhe (Koodi=0x{0:X8})")
            .sv("Sönder (Kod=0x{0:X8})");

    public void DoOk()
    {
        Console.WriteLine( ok );
    }

    public void DoError()
    {
        Console.WriteLine( error.Value(0x100) );
    }
}

¹ (jestem opiekunem tej biblioteki)

Etykietka
źródło
0

Zasadniczo umieszczasz swoje tłumaczenia w plikach zasobów, np. Resources.resx.

Każda konkretna kultura ma inną nazwę, np. Resources.nl.resx, resources.fr.resx, resources.de.resx,…

Teraz najważniejszą częścią rozwiązania jest utrzymanie tłumaczeń. W Visual Studio zainstaluj narzędzie Microsoft MAT: Multilingual App Toolkit (MAT). Działa z winforms, wpf, asp.net (core), uwp,…

Ogólnie, np. Dla rozwiązania WPF, w projekcie WPF

  • Zainstaluj rozszerzenie Microsoft MAT dla Visual Studio.
  • W Eksploratorze rozwiązań przejdź do projektu> Właściwości> AssemblyInfo.cs
  • Dodaj w AssemblyInfo.cs domyślny, neutralny język (w moim przypadku angielski): [assembly: System.Resources.NeutralResourcesLanguage("en")]
  • Wybierz projekt w Eksploratorze rozwiązań i Visual Studio, w górnym menu kliknij „Narzędzia”> „Multilingual App Toolkit”> „Enable Selection”, aby włączyć MAT dla projektu.
    • Teraz kliknij prawym przyciskiem myszy projekt w Eksploratorze rozwiązań, wybierz „Multilingual App Toolkit”> „Dodaj języki tłumaczenia…” i wybierz język, dla którego chcesz dodać tłumaczenia. np. holenderski

Zobaczysz, że zostanie utworzony nowy folder o nazwie „MultilingualResources” zawierający ....nl.xlfplik.

Jedyne, co musisz teraz zrobić, to:

  1. dodaj swoje tłumaczenie do domyślnego pliku resources.resx (w moim przypadku angielski)
  2. Przetłumacz, klikając plik .xlf (NIE plik .resx), ponieważ pliki .xlf wygenerują / zaktualizują pliki .resx.

(pliki .xlf powinny otwierać się za pomocą „Multilingual Editor”, jeśli tak nie jest, kliknij prawym przyciskiem myszy plik .xlf, wybierz „Otwórz za pomocą…” i wybierz „Multilingual Editor”.

Baw się dobrze! teraz możesz także zobaczyć to, co nie zostało przetłumaczone, wyeksportować tłumaczenia w formacie xlf do zewnętrznych biur tłumaczeń, zaimportować je ponownie, przetłumaczyć tłumaczenia z innych projektów itp.

Więcej informacji:

juFo
źródło