diff --git a/.gitignore b/.gitignore index 2d6e59ab6..d4d5b0560 100644 --- a/.gitignore +++ b/.gitignore @@ -48,5 +48,6 @@ bam.exe *.cmd .settings *.opensdf +*.pyc DDNet* diff --git a/data/languages/german.txt b/data/languages/german.txt index 074691a5d..a2efd6b70 100644 --- a/data/languages/german.txt +++ b/data/languages/german.txt @@ -18,13 +18,11 @@ # heinrich5991 2011-07-02 09:10:21 # Yared Hufkens 2012-02-03 19:57:59 # andi103 2012-07-14 11:31:11 +# DoNe 2014-06-30 18:26:59 ##### /authors ##### ##### translated strings ##### -%d%% loaded -== %d%% geladen - %ds left == Noch %ds @@ -61,9 +59,6 @@ Address All == Alle -Always show name plates -== Spielernamen immer anzeigen - Are you sure that you want to delete the demo? == Möchtest du die Aufnahme wirklich löschen? @@ -79,9 +74,6 @@ As this is the first time you launch the game, please enter your nick name below Automatically record demos == Automatisch Aufnahmen erstellen -Automatically take game over screenshot -== Autom. ein Bild vom Spielergebnis erstellen - Blue team == Blaues Team @@ -268,9 +260,6 @@ Kick player Language == Sprache -Loading -== Laden - MOTD == Nachricht des Tages @@ -442,9 +431,6 @@ Server info Server not full == Server nicht voll -Settings -== Optionen - Shotgun == Schrotflinte @@ -514,9 +500,6 @@ Team Team chat == Teamchat -Teeworlds %s is out! Download it at www.teeworlds.com! -== Teeworld %s ist da! Lade es unter www.teeworlds.com runter! - Texture Compression == Texturkompression @@ -578,7 +561,7 @@ Warmup == Aufwärmen Weapon -== Waffe +== Waffen Welcome to Teeworlds == Willkommen bei Teeworlds @@ -591,320 +574,6 @@ You must restart the game for all settings to take effect. ##### needs translation ##### -%.3f KiB -== - -%d player left -== - -%d player not ready -== - -%d players left -== - -%d players not ready -== - -%d servers, %d players -== - -'%s' called for vote to kick '%s' (%s) -== - -'%s' called for vote to move '%s' to spectators (%s) -== - -'%s' called vote to change server option '%s' (%s) -== - -'%s' entered and joined the %s -== - -'%s' has left the game -== - -'%s' has left the game (%s) -== - -'%s' joined the %s -== - -Admin forced server option '%s' (%s) -== - -Admin forced vote no -== - -Admin forced vote yes -== - -Admin moved '%s' to spectator (%s) -== - -Alp: -== - -Anti Aliasing -== - -Are you sure you want to rename the demo? -== - -Are you sure you want to save your skin? If a skin with this name already exists, it will be replaced. -== - -Back -== - -Basic -== - -Bodies -== - -Borderless window -== - -Color -== - -Crc -== - -Created -== - -Custom -== - -Customize -== - -Decoration -== - -Demo -== - -Detail -== - -Editor -== - -Eyes -== - -Format -== - -Game starts in -== - -Global -== - -Hands -== - -Host address: -== - -Hue: -== - -Join -== - -Joined -== - -Joined blue -== - -Joined red -== - -Kick voting requires %d players on the server -== - -Laser -== - -Length -== - -Letterbox -== - -Lgt: -== - -Local -== - -Local server -== - -Match -== - -Max -== - -Misc -== - -Netversion -== - -Nickname is empty. -== - -Normal: -== - -Only %d active players are allowed -== - -Personal -== - -Ready -== - -Record -== - -Recorded -== - -Reset -== - -Resolutions -== - -Round over -== - -Round over! -== - -Sat: -== - -Save -== - -Save skin -== - -Screen -== - -Search: -== - -Server does not allow voting to kick players -== - -Server does not allow voting to move players to spectators -== - -Servers -== - -Size -== - -Skin -== - -Spectating -== - -Spectators aren't allowed to start a vote. -== - -Standard Gametype -== - -Tattoo -== - -Tattoos -== - -Team: -== - -Teams are locked -== - -Teams are locked. Time to wait before changing team: %02d:%02d -== - -Teams were locked -== - -Teams were unlocked -== - -Tee -== - -Texture -== - -Volume -== - -Vote aborted -== - -Vote failed -== - -Vote passed -== - -Wait for current vote to end before calling a new one. -== - -Wait for next round -== - -Wide -== - -You must wait %d seconds before making another vote -== - -blue -== - -blue team -== - -game -== - -red -== - -red team -== - -spectators -== - -wait for more players -== - -##### old translations ##### - New name: == Neuer Name: @@ -944,27 +613,15 @@ Max Screenshots Length: == Länge -Skin name -== - Rifle == Laser -Patterns -== - Netversion: == Netversion: Map: == Karte: -%d Bytes -== %d Bytes - -Coloration -== - Info == Info @@ -981,7 +638,7 @@ Size: == Größe:  -== ## translated strings ##### +##### translated strings ##### Reset to defaults == Standardeinstellung @@ -1004,9 +661,6 @@ Lht. no limit == Keine Begrenzung -Quick search: -== Schnellsuche: - UI Color == Menüfarbe @@ -1019,9 +673,6 @@ Crc: Alpha == Alpha -Are you sure you want to save your skin ? If a skin with this name already exists, it will be replaced. -== - Current version: %s == Aktuelle Version: %s @@ -1034,3 +685,251 @@ Name plates size Type: == Typ: +Automatically take game over statboard screenshot +== Automatisch Screenshots vom Statboard am Spielende erstellen + +Ratio +== Ratio + +Dummy settings +== Einstellungen für Dummy + +AntiPing +== AntiPing + +Show quads +== Quads anzeigen + +✎ +== ✎ + +Map sound volume +== Lautstärke von Mapsounds + +✗ +== ✗ + +Countries +== Ländern + +Inner color +== Innere Farbe + +CPU Throttle +== CPU Limit + +\n\nReconnect in %d sec +== Neu verbinden in %d Sekunden + +Background (entities) +== Hintergrund (Entities) + +Show kill messages +== Kill-Nachrichten anzeigen + +Show ghost +== Geist anzeigen + +No updates available +== Keine neuen Versionen verfügbar + +Update now +== Jetzt aktualisieren + +Enable server message sound +== Aktiviere Ton für Server-Nachrichten + +second +== Sekunde + +Show votes window after voting +== Zeige Vote-Fenster nach dem Voten + +HUD +== Aussehen + +Look out! +== Pass auf! + +Show names in chat in team colors +== Nutze Teamfarben im Chat + +Enable team chat sound +== Aktiviere Ton für Team-Nachrichten + +Show other players' hook collision lines +== Hook-Collision von anderen Spielern anzeigen + +We will win +== Wir werden gewinnen + +Deaths +== Tode + +Enable game sounds +== Aktiviere Ton im Spiel + +DDNet Client needs to be restarted to complete update! +== Der DDNet Client muss neu gestarted werden um das Update abzuschließen! + +Spectator +== Zuschauer + +Show others +== Andere Teams zeigen + +Restart +== Neustart + +Browser +== Browser + +Automatically take game over scoreboard screenshot +== Automatisch Screenshots vom Scoreboard am Spielende erstellen + +⚲ +== ⚲ + +Enable gun sound +== Aktiviere Pistolen-Ton + +Show health + ammo +== Gesundheit und Munition anzeigen + +Team message +== Team-Nachricht + +Save the best demo of each race +== Speichere die beste Aufnahme von jedem Race + +Outline color +== Äußere Farbe + +Are you sure that you want to disconnect? +== Bist du sicher, dass du die Verbindung trennen möchtest? + +Ghost +== Geist + +Check now +== Aktualisieren + +DDNet Client updated! +== Der DDNet Client wurde aktualisiert! + +Background (regular) +== Hintergrund (Normal) + +AntiPing: predict other players +== AntiPing: Berechne andere Spieler vor + +Show other players' key presses +== Tastendrücke von anderen Spielern anzeigen + +System message +== Server-Nachricht + +DDNet %s is available: +== DDNet %s ist verfügbar: + +Updating... +== Aktualisieren... + +Overlay entities +== Entities Overlay + +Messages +== Nachrichten + +%.2f MiB +== %.2f MiB + +Dummy Timeout code +== Timeout-Code für Dummy + +Suicides +== Selbstmorde + +Timeout code +== Timeout-Code + +Use DDRace Scoreboard +== Benutze das DDRace Scoreboard + +DDNet %s is out! Download it at ddnet.tw! +== DDNet %s ist jetzt auf ddnet.tw verfügbar! + +Loading DDNet Client +== Lade DDNet Client + +Default zoom +== Normal-Zoom + +Show score +== Score anzeigen + +Spree +== Killfolge + +Show client IDs in Scoreboard +== Client IDs im Scoreboard anzeigen + +seconds +== Sekunden + +Show new skins ingame +== Zeige neue Skins im Spiel + +%.2f KiB +== %.2f KiB + +Try fast HTTP map download first +== Probiere schnelleres Downloaden über HTTP + +Enable regular chat sound +== Aktiviere Ton für normale Nachrichten + +DDNet +== DDNet + +Normal message +== Normale Nachricht + +Best spree +== Beste Killfolge + +AntiPing: predict grenade paths +== AntiPing: Berechne Granaten-Flugkurve vor + +Search +== Suche + +Connecting dummy +== Dummy verbindet sich + +Show clan above name plates +== Clan über Spielernamen anzeigen + +Save ghost +== Geist speichern + +Enable highlighted chat sound +== Aktiviere Ton für Nachrichten an dich + +AntiPing: predict weapons +== AntiPing: Berechne Waffen vor + +Hello and welcome +== Hallo und willkommen + +Highlighted message +== Nachricht an dich + +Reset wanted weapon on death +== Waffe beim Tod zurücksetzen + +Switch weapon when out of ammo +== Waffe wechseln wenn die Munition leer ist + +AntiPing limit +== AntiPing-Limit diff --git a/data/languages/italian.txt b/data/languages/italian.txt index 30768bdc8..8d6be55fd 100644 --- a/data/languages/italian.txt +++ b/data/languages/italian.txt @@ -969,8 +969,7 @@ Your skin Size: == Dimensione: - -== ## translated strings ##### +##### translated strings ##### Reset to defaults == Reimposta diff --git a/data/languages/polish.txt b/data/languages/polish.txt index d85a8f5fb..bc9713306 100644 --- a/data/languages/polish.txt +++ b/data/languages/polish.txt @@ -923,9 +923,6 @@ FSAA samples Sound volume == Głośność - -== - Created: == Utworzono: @@ -1212,4 +1209,4 @@ none == żadne DDNet Client needs to be restarted to complete update! -== DDNet Client wymaga ponownego uruchomienia, aby zakończyć aktualizację! \ No newline at end of file +== DDNet Client wymaga ponownego uruchomienia, aby zakończyć aktualizację! diff --git a/data/languages/scripts/analyze.py b/data/languages/scripts/analyze.py new file mode 100644 index 000000000..ea51107be --- /dev/null +++ b/data/languages/scripts/analyze.py @@ -0,0 +1,31 @@ +import twlang +import sys + +if len(sys.argv) > 1: + langs = sys.argv[1:] +else: + langs = twlang.languages() +local = twlang.localizes() +table = [] +for lang in langs: + trans = twlang.translations(lang) + empty = 0 + supported = 0 + unused = 0 + for tran, (_, expr, _) in trans.iteritems(): + if not expr: + empty += 1 + else: + if tran in local: + supported += 1 + else: + unused += 1 + table.append([lang, len(trans), empty, len(local)-supported, unused]) + +table.sort(key=lambda l: l[3]) +table = [["filename", "total", "empty", "missing", "unused"]] + table +s = [[str(e) for e in row] for row in table] +lens = [max(map(len, col)) for col in zip(*s)] +fmt = " ".join("{{:{}}}".format(x) for x in lens) +t = [fmt.format(*row) for row in s] +print("\n".join(t)) diff --git a/data/languages/scripts/copy_fix.py b/data/languages/scripts/copy_fix.py new file mode 100644 index 000000000..5be648bfd --- /dev/null +++ b/data/languages/scripts/copy_fix.py @@ -0,0 +1,49 @@ +import twlang +import sys + +if len(sys.argv) < 3: + print("usage: python copy_fix.py [--delete-unused] [--append-missing] [--delete-empty]") + sys.exit() +infile = sys.argv[1] +outfile = sys.argv[2] +args = sys.argv[3:] +delete_unused = False +append_missing = False +delete_empty = False +for arg in args: + if arg == "--delete-unused": + delete_unused = True + elif arg == "--append-missing": + append_missing = True + elif arg == "--delete-empty": + delete_empty = True + else: + print("No such argument '"+arg+"'.") + sys.exit() + +content = open(infile).readlines() +trans = twlang.translations(infile) +if delete_unused or append_missing: + local = twlang.localizes() +if append_missing: + supported = [] +for tran, (start, expr, end) in trans.iteritems(): + if delete_unused and tran not in local: + content[start:end] = [None]*(end-start) + if append_missing and tran in local: + if expr or (not expr and delete_empty): + supported.append(local.index(tran)) + else: + content[start:end] = [None]*(end-start) + if delete_empty and not expr: + content[start:end] = [None]*(end-start) +content = [line for line in content if line != None] +if append_missing: + missing = [index for index in range(len(local)) if index not in supported] + if missing: + content.append("\n##### generated by copy_fix.py, please translate this #####\n") + for miss in missing: + content.append("\n"+local[miss]+"\n== \n") + +open(outfile, "w").write("".join(content)) +print("Successfully created '"+outfile+"'.") diff --git a/data/languages/scripts/find_unchanged.py b/data/languages/scripts/find_unchanged.py new file mode 100644 index 000000000..6fddadc0d --- /dev/null +++ b/data/languages/scripts/find_unchanged.py @@ -0,0 +1,12 @@ +import twlang +import sys + +if len(sys.argv) < 2: + print("usage: python find_unchanged.py ") + sys.exit() +infile = sys.argv[1] + +trans = twlang.translations(infile) +for tran, (_, expr, _) in trans.iteritems(): + if tran == expr: + print(tran) diff --git a/data/languages/scripts/readme.txt b/data/languages/scripts/readme.txt new file mode 100644 index 000000000..df935bba0 --- /dev/null +++ b/data/languages/scripts/readme.txt @@ -0,0 +1,37 @@ +Teeworlds language scripts by DoNe + +These scripts can help you to improve the language files. This is a short tutorial +about how to use the scripts. + + +You can start by analyzing the current languages using analyze.py +$ python analyze.py + +analyze.py outputs serveral columns. The column 'total' is the number of +translations in the file. 'empty' is the number of untranslated phrases in the +file. The 2nd and 3rd columns are calculated by looking into the source. The scirpt +searches through the source for all phrases. 'missing' is the number of phrases in +the source but not in the file. 'unused' is the number of phrases in the file but +not in the source. + + +To update a language you should first copy it using the copy_fix.py script. +$ python copy_fix.py ../spanish.txt newspanish.txt --delete-unused --append-missing + +Then you can start to modify newspanish.txt. Search in the file for the following +line and remove it: +##### generated by copy_fix.py, please translate this ##### + +Every phrase below this line should be empty. Now you can fill in the translations +you know. It's also okay to write just the same phrase as in english for words like +'Hookcollision' or 'Screenshot'. If you don't know how to translate something just +remove it. + +That's all, you improved the translation. If you want you can add your name at the +start of the file. Now you can move the file back to its original location. +$ mv newspanish.txt ../spanish.txt + + +Often people know bette phrases for translations where the english phrase was just +written again. To find these you can use find_unchanged.py +$ python find_unchanged.py ../spanish.txt diff --git a/data/languages/scripts/twlang.py b/data/languages/scripts/twlang.py new file mode 100644 index 000000000..cc3e7f8cc --- /dev/null +++ b/data/languages/scripts/twlang.py @@ -0,0 +1,72 @@ +import os +import re + + +class LanguageDecodeError(Exception): + def __init__(self, message, filename, line): + error = "File \"{1}\", line {2}: {0}".format(message, filename, line+1) + super(LanguageDecodeError, self).__init__(error) + + +def decode(fileobj, elements_per_key): + data = {} + current_key = None + for index, line in enumerate(fileobj): + line = line.decode("utf-8-sig").encode("utf-8") + line = line[:-1] + if not line or line[:1] == "#": + continue + if line[:3] == "== ": + if len(data[current_key]) >= 1+elements_per_key: + raise LanguageDecodeError("Wrong number of elements per key", fileobj.name, index) + if current_key: + data[current_key].extend([line[3:]]) + else: + raise LanguageDecodeError("Element before key given", fileobj.name, index) + else: + if current_key: + if len(data[current_key]) != 1+elements_per_key: + raise LanguageDecodeError("Wrong number of elements per key", fileobj.name, index) + data[current_key].append(index) + if line in data: + raise LanguageDecodeError("Key defined multiple times", fileobj.name, index) + data[line] = [index] + current_key = line + if len(data[current_key]) != 1+elements_per_key: + raise LanguageDecodeError("Wrong number of elements per key", fileobj.name, index) + data[current_key].append(index+1) + return data + + +def check_file(path): + with open(path) as fileobj: + matches = re.findall("Localize\s*\(\s*\"([^\"]+)\"\s*\)", fileobj.read()) + return matches + + +def check_folder(path): + files = os.listdir(path) + englishlist = set() + for f in files: + newpath = os.path.join(path, f) + if os.path.isdir(newpath): + englishlist.update(check_folder(newpath)) + elif os.path.isfile(newpath): + englishlist.update(check_file(newpath)) + return englishlist + + +def languages(): + index = decode(open("../index.txt"), 2) + langs = {"../"+key+".txt" : [key]+elements for key, elements in index.iteritems()} + return langs + + +def translations(filename): + translations = decode(open(filename), 1) + return translations + + +def localizes(): + englishlist = list(check_folder("../../../src")) + return englishlist diff --git a/data/languages/turkish.txt b/data/languages/turkish.txt index 5412bb5e7..a5b5ba1a8 100644 --- a/data/languages/turkish.txt +++ b/data/languages/turkish.txt @@ -968,8 +968,7 @@ Your skin Size: == Boyut: - -== ## translated strings ##### +##### translated strings ##### Reset to defaults == Varsayılanlara getir diff --git a/src/game/client/components/menus_browser.cpp b/src/game/client/components/menus_browser.cpp index cc41e7655..3d6745147 100644 --- a/src/game/client/components/menus_browser.cpp +++ b/src/game/client/components/menus_browser.cpp @@ -1316,7 +1316,7 @@ void CMenus::RenderServerbrowser(CUIRect MainView) TextRender()->TextColor(1.0f, 0.4f, 0.4f, 1.0f); } else - str_format(aBuf, sizeof(aBuf), Localize("Current Version: %s"), GAME_VERSION); + str_format(aBuf, sizeof(aBuf), Localize("Current version: %s"), GAME_VERSION); UI()->DoLabelScaled(&Button, aBuf, 14.0f, -1); TextRender()->TextColor(1.0f, 1.0f, 1.0f, 1.0f); #endif