2

Ich suche nach einer Möglichkeit, die Sprache im laufenden Betrieb einzustellen, wenn Sie eine Übersetzung für eine Zeichenkette in gettext anfordern. Ich werde erklären, warum:Python gettext: Gebietsschema in _ angeben()

Ich habe einen Multithread-Bot, die auf Benutzer durch Text auf mehreren Servern reagieren und so in verschiedenen Sprachen antworten müssen. Die documentation von gettext besagt, dass locale zu ändern, während ausführen, sollten Sie Folgendes tun:

import gettext # first, import gettext 

lang1 = gettext.translation('myapplication', languages=['en']) # Load every translations 
lang2 = gettext.translation('myapplication', languages=['fr']) 
lang3 = gettext.translation('myapplication', languages=['de']) 

# start by using language1 
lang1.install() 

# ... time goes by, user selects language 2 
lang2.install() 

# ... more time goes by, user selects language 3 
lang3.install() 

Aber dies gilt nicht, in meinem Fall, da der Bot multithreaded ist:

die 2 Stellen Sie sich vor folgende Schnipsel zur gleichen Zeit ausgeführt werden:

import time 
import gettext 
lang1 = gettext.translation('myapplication', languages=['fr']) 
lang1.install() 
message(_("Loading a dummy task")) # This should be in french, and it will 
time.sleep(10) 
message(_("Finished loading")) # This should be in french too, but it wont :'(

und

import time 
import gettext 
lang = gettext.translation('myapplication', languages=['en']) 
time.sleep(3) # Not requested on the same time 
lang.install() 
message(_("Loading a dummy task")) # This should be in english, and it will 
time.sleep(10) 
message(_("Finished loading")) # This should be in english too, and it will 

Sie können sehen, dass Nachrichten manchmal in der falschen Ländereinstellung übersetzt werden. Aber wenn ich etwas wie _("string", lang="FR") tun könnte, würde das Problem verschwinden!

Habe ich etwas verpasst, oder ich das falsche Modul mit der Aufgabe zu tun ... Ich verwende python3

+0

Vielleicht habe ich meine Frage schlecht formuliert? Wie kann ich es verbessern? – WayToDoor

+0

Sie haben nicht genügend Informationen zur Verfügung gestellt, damit jemand Ihr Problem problemlos reproduzieren kann.Ich musste herausfinden, wie man 'gettext' verwendet und ein minimales Übersetzungssetup erstellt. Im Idealfall würden Sie eine [MCVE] bereitstellen. –

+0

Verwenden Sie einfach nicht 'install' offensichtlich ... rufen Sie' gettext' direkt auf den Instanzen auf. (mit 'Builtins' zu spielen ist sowieso böse). – o11c

Antwort

1

Das folgende einfache Beispiel zeigt, wie für jeden Übersetzer einen separaten Prozess verwenden:

import gettext 
import multiprocessing 
import time 

def translation_function(language): 
    try: 
     lang = gettext.translation('simple', localedir='locale', languages=[language]) 
     lang.install() 
     while True: 
      print(_("Running translator"), ": %s" % language) 
      time.sleep(1.0) 
    except KeyboardInterrupt: 
     pass 

if __name__ == '__main__': 
    thread_list = list() 
    try: 
     for lang in ['en', 'fr', 'de']: 
      t = multiprocessing.Process(target=translation_function, args=(lang,)) 
      t.daemon = True 
      t.start() 
      thread_list.append(t) 
     while True: 
      time.sleep(1.0) 
    except KeyboardInterrupt: 
     for t in thread_list: 
      t.join() 

Die Ausgabe sieht wie folgt aus:

 
Running translator : en 
Traducteur en cours d’exécution : fr 
Laufenden Übersetzer : de 
Running translator : en 
Traducteur en cours d’exécution : fr 
Laufenden Übersetzer : de 

Wenn ich dies mit Threads versucht, ich eine englische Übersetzung nur bekam. Sie können in jedem Prozess einzelne Threads erstellen, um Verbindungen zu verwalten. Wahrscheinlich möchten Sie nicht für jede Verbindung einen neuen Prozess erstellen.

+0

Danke, das hat sich bewährt: Ich verstehe jetzt das Gettext-Modul besser! Habe meine Erwiderung. Ich bleibe bei der @ o11c-Lösung, weil es Multithreading besser beherrscht! – WayToDoor

1

Ich brauchte einen Moment, um ein Skript zu erstellen, das die auf dem System verfügbaren Gebietsschemas verwendet, und versucht, eine bekannte Nachricht in ihnen zu drucken. Beachten Sie, dass "alle Gebietsschemen" nur Codierungsänderungen enthalten, die von Python sowieso negiert werden, und viele Übersetzungen unvollständig sind. Verwenden Sie also das Fallback.

Offensichtlich müssen Sie auch entsprechende Änderungen an Ihrer Verwendung von xgettext (oder gleichwertig) für Ihren echten Code vornehmen, um die Übersetzungsfunktion zu identifizieren.

#!/usr/bin/env python3 

import gettext 
import os 

def all_languages(): 
    rv = [] 
    for lang in os.listdir(gettext._default_localedir): 
     base = lang.split('_')[0].split('.')[0].split('@')[0] 
     if 2 <= len(base) <= 3 and all(c.islower() for c in base): 
      if base != 'all': 
       rv.append(lang) 
    rv.sort() 
    rv.append('C.UTF-8') 
    rv.append('C') 
    return rv 

class Domain: 
    def __init__(self, domain): 
     self._domain = domain 
     self._translations = {} 

    def _get_translation(self, lang): 
     try: 
      return self._translations[lang] 
     except KeyError: 
      # The fact that `fallback=True` is not the default is a serious design flaw. 
      rv = self._translations[lang] = gettext.translation(self._domain, languages=[lang], fallback=True) 
      return rv 

    def get(self, lang, msg): 
     return self._get_translation(lang).gettext(msg) 

def print_messages(domain, msg): 
    domain = Domain(domain) 
    for lang in all_languages(): 
     print(lang, ':', domain.get(lang, msg)) 

def main(): 
    print_messages('libc', 'No such file or directory') 

if __name__ == '__main__': 
    main() 
+0

Danke! Dies war nützlich. Ich habe Ihre Domain-Klasse verwendet, und es funktioniert wie ein Zauber. Mit ein paar Modifikationen konnte ich die Sprache in der Funktion _ einstellen! – WayToDoor

1

Das folgende Beispiel verwendet die translation direkt, wie in o11c'sanswer gezeigt, dass die Verwendung von Threads zu ermöglichen:

import gettext 
import threading 
import time 

def translation_function(quit_flag, language): 
    lang = gettext.translation('simple', localedir='locale', languages=[language]) 
    while not quit_flag.is_set(): 
     print(lang.gettext("Running translator"), ": %s" % language) 
     time.sleep(1.0) 

if __name__ == '__main__': 
    thread_list = list() 
    quit_flag = threading.Event() 
    try: 
     for lang in ['en', 'fr', 'de']: 
      t = threading.Thread(target=translation_function, args=(quit_flag, lang,)) 
      t.daemon = True 
      t.start() 
      thread_list.append(t) 
     while True: 
      time.sleep(1.0) 
    except KeyboardInterrupt: 
     quit_flag.set() 
     for t in thread_list: 
      t.join() 

Ausgang:

 
Running translator : en 
Traducteur en cours d’exécution : fr 
Laufenden Übersetzer : de 
Running translator : en 
Traducteur en cours d’exécution : fr 
Laufenden Übersetzer : de 

Ich würde diese Beiträge geschrieben haben antworte, wenn ich mehr über gewusst hätte. Ich verlasse meine vorherige Antwort für Leute, die wirklich weiter verwenden möchten _().