2816: Implement context for translations (largely taken from Teeworlds) r=Learath2 a=def-

Missing: scripts/languages doesn't work yet, but the context can be
added manually, see german.txt for an example.

Co-authored-by: def <dennis@felsin9.de>
This commit is contained in:
bors[bot] 2020-09-15 17:02:00 +00:00 committed by GitHub
commit 3b0bb7d777
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
38 changed files with 454 additions and 181 deletions

View file

@ -307,6 +307,7 @@ Ping
Pistol Pistol
== Пісталет == Пісталет
[Demo browser]
Play Play
== Прагляд == Прагляд
@ -1158,6 +1159,10 @@ Server executable not found, can't run server
Editor Editor
== ==
[Start menu]
Play
==
DDNet %s is out! DDNet %s is out!
== ==

View file

@ -310,6 +310,7 @@ Ping
Pistol Pistol
== Pištolj == Pištolj
[Demo browser]
Play Play
== Pogledaj == Pogledaj
@ -1206,6 +1207,10 @@ Server executable not found, can't run server
Editor Editor
== ==
[Start menu]
Play
==
Manual %3d:%02d Manual %3d:%02d
== ==

View file

@ -325,6 +325,7 @@ Ping
Pistol Pistol
== Pistola == Pistola
[Demo browser]
Play Play
== Assistir == Assistir
@ -1236,3 +1237,7 @@ Server executable not found, can't run server
Editor Editor
== ==
[Start menu]
Play
==

View file

@ -307,6 +307,7 @@ Ping
Pistol Pistol
== Пистолет == Пистолет
[Demo browser]
Play Play
== Възпроизведи == Възпроизведи
@ -1158,6 +1159,10 @@ Server executable not found, can't run server
Editor Editor
== ==
[Start menu]
Play
==
DDNet %s is out! DDNet %s is out!
== ==

View file

@ -305,6 +305,7 @@ Ping
Pistol Pistol
== Pistola == Pistola
[Demo browser]
Play Play
== Reproduir == Reproduir
@ -1216,3 +1217,7 @@ Server executable not found, can't run server
Editor Editor
== ==
[Start menu]
Play
==

View file

@ -307,6 +307,7 @@ Ping
Pistol Pistol
== Пистолет == Пистолет
[Demo browser]
Play Play
== Пăхма == Пăхма
@ -1158,6 +1159,10 @@ Server executable not found, can't run server
Editor Editor
== ==
[Start menu]
Play
==
DDNet %s is out! DDNet %s is out!
== ==

View file

@ -310,6 +310,7 @@ Ping
Pistol Pistol
== Pistolka == Pistolka
[Demo browser]
Play Play
== Přehrát == Přehrát
@ -1161,6 +1162,10 @@ Server executable not found, can't run server
Editor Editor
== ==
[Start menu]
Play
==
DDNet %s is out! DDNet %s is out!
== ==

View file

@ -307,6 +307,7 @@ Ping
Pistol Pistol
== Pistol == Pistol
[Demo browser]
Play Play
== Spil == Spil
@ -1158,6 +1159,10 @@ Server executable not found, can't run server
Editor Editor
== ==
[Start menu]
Play
==
DDNet %s is out! DDNet %s is out!
== ==

View file

@ -319,6 +319,7 @@ Ping
Pistol Pistol
== Pistool == Pistool
[Demo browser]
Play Play
== Spelen == Spelen
@ -1229,6 +1230,10 @@ Server executable not found, can't run server
Editor Editor
== ==
[Start menu]
Play
==
Net Net
== ==

View file

@ -308,6 +308,7 @@ Ping
Pistol Pistol
== Pistooli == Pistooli
[Demo browser]
Play Play
== Toista == Toista
@ -1159,6 +1160,10 @@ Server executable not found, can't run server
Editor Editor
== ==
[Start menu]
Play
==
DDNet %s is out! DDNet %s is out!
== ==

View file

@ -319,6 +319,7 @@ Ping
Pistol Pistol
== Pistolet == Pistolet
[Demo browser]
Play Play
== Jouer == Jouer
@ -1247,3 +1248,7 @@ Server executable not found, can't run server
Editor Editor
== ==
[Start menu]
Play
==

View file

@ -324,6 +324,7 @@ Ping
Pistol Pistol
== Pistole == Pistole
[Demo browser]
Play Play
== Abspielen == Abspielen
@ -1225,16 +1226,20 @@ Menu
== Menü == Menü
Warning Warning
== == Warnung
Speed Speed
== == Geschwindigkeit
Website
== Website
Server executable not found, can't run server
== Server-Programm nicht gefunden, kann Server nicht starten
[Start menu]
Play
== Spielen
https://wiki.ddnet.tw/ https://wiki.ddnet.tw/
== ==
Website
==
Server executable not found, can't run server
==

View file

@ -310,6 +310,7 @@ Ping
Pistol Pistol
== Πιστόλι == Πιστόλι
[Demo browser]
Play Play
== Παίξτε == Παίξτε
@ -1158,6 +1159,10 @@ Server executable not found, can't run server
Editor Editor
== ==
[Start menu]
Play
==
DDNet %s is out! DDNet %s is out!
== ==

View file

@ -304,6 +304,7 @@ Ping
Pistol Pistol
== Pisztoly == Pisztoly
[Demo browser]
Play Play
== Játék == Játék
@ -1228,3 +1229,7 @@ Server executable not found, can't run server
Editor Editor
== ==
[Start menu]
Play
==

View file

@ -311,6 +311,7 @@ Ping
Pistol Pistol
== Pistola == Pistola
[Demo browser]
Play Play
== Riproduci == Riproduci
@ -1164,6 +1165,10 @@ Server executable not found, can't run server
Editor Editor
== ==
[Start menu]
Play
==
DDNet %s is out! DDNet %s is out!
== ==

View file

@ -307,6 +307,7 @@ Ping
Pistol Pistol
== ピストル == ピストル
[Demo browser]
Play Play
== プレイ == プレイ
@ -1158,6 +1159,10 @@ Server executable not found, can't run server
Editor Editor
== ==
[Start menu]
Play
==
DDNet %s is out! DDNet %s is out!
== ==

View file

@ -303,6 +303,7 @@ Ping
Pistol Pistol
== 권총 == 권총
[Demo browser]
Play Play
== 플레이 == 플레이
@ -1157,6 +1158,10 @@ Server executable not found, can't run server
Editor Editor
== ==
[Start menu]
Play
==
DDNet %s is out! DDNet %s is out!
== ==

View file

@ -366,6 +366,7 @@ Ping
Pistol Pistol
== Тапанча == Тапанча
[Demo browser]
Play Play
== Көрүү == Көрүү
@ -1149,6 +1150,10 @@ Server executable not found, can't run server
Editor Editor
== ==
[Start menu]
Play
==
DDNet %s is out! DDNet %s is out!
== ==

View file

@ -308,6 +308,7 @@ Ping
Pistol Pistol
== Pistol == Pistol
[Demo browser]
Play Play
== Spill == Spill
@ -1224,3 +1225,7 @@ Server executable not found, can't run server
Editor Editor
== ==
[Start menu]
Play
==

View file

@ -204,157 +204,9 @@ Ping
== ﮓﻨﯿﭘ == ﮓﻨﯿﭘ
Pistol Pistol
== ﺮﯿﺗ ﺖﻔﻫ == ﺮﯿﺗ ﺖﻔﻫ
[Demo browser]
Play Play
== ﻥﺩﺮﻛ ىﺯﺎﺑ == ﻥﺩﺮﻛ ىﺯﺎﺑ
Play background music
== ﻪﻨﯿﻣﺯ ﺲﭘ ﻚﯾﺯﻮﻣ ﻥﺩﺮﻛ ﺶﺨﭘ
Player
== ﻦﻜﯾﺯﺎﺑ
Player country:
== ﻦﻜﯾﺯﺎﺑ ﺭﻮﺸﻛ:
Player options
== ﻦﻜﯾﺯﺎﺑ ﺕﺎﻤﯿﻈﻨﺗ:
Players
== ﻥﺎﻨﻜﯾﺯﺎﺑ
Please balance teams!
== !ﺪﯿﻨﻛ ﻝﺩﺎﻌﺘﻣ ﺍﺭ ﻢﯿﺗ ﺎﻔﻄﻟ
Prev. weapon
== ﯽﻠﺒﻗ ﻪﺤﻠﺳﺍ
Quit
== ﻥﺪﺷ ﺝﺭﺎﺧ
Reason:
== ﻞﯿﻟﺩ:
Red team
== ﺰﻣﺮﻗ ﻢﯿﺗ
Red team wins!
== !ﺪﺷ ﻩﺪﻧﺮﺑ ﺰﻣﺮﻗ ﻢﯿﺗ
Refresh
== ﻩﺭﺎﺑﻭﺩ ىﺭﺍﺬﮔﺭﺎﺑ
Refreshing master servers
== ﯽﻠﺻﺍ ىﺎﻫ ﺭﻭﺮﺳ ﻩﺭﺎﺑﻭﺩ ىﺭﺍﺬﮔﺭﺎﺑ
Remote console
== ﻝﻮﺴﻨﮐ ﻝﺮﺘﻨﮐ
Remove
== ﻥﺩﺮﮐ ﻑﺬﺣ
Remove friend
== ﺖﺳﻭﺩ ﻥﺩﺮﮐ ﻑﺪﺣ
Rename
== ﻡﺎﻧ ﺮﯿﯿﻐﺗ
Rename demo
== ﻮﻣﺩ ﻡﺎﻧ ﺮﯿﯿﻐﺗ
Reset filter
== ﺮﺘﻠﯿﻓ ﻩﺭﺎﺑﻭﺩ ﻢﯿﻈﻨﺗ
Sample rate
== ﻪﻧﻮﻤﻧ ﺶﺠﻨﺳ
Score
== ﺯﺎﯿﺘﻣﺍ
Score limit
== ﺯﺎﯿﺘﻣﺍ ﺪﺣ
Scoreboard
== ﯼﺪﻨﺑ ﻪﺒﺗﺭ
Screenshot
== ﻪﺤﻔﺻ ﺯﺍ ﯼﺭﺍﺩﺮﺑ ﺲﮑﻋ
Server address:
== :ﺭﻭﺮﺳ ﺱﺭﺩﺁ
Server details
== ﺭﻭﺮﺳ ﺕﺎﯿﺋﺰﺟ
Server filter
== ﺭﻭﺮﺳ ﯽﮔﮋﯾﻭ
Server info
== ﺭﻭﺮﺳ ﺕﺎﻋﻼﻃﺍ
Server not full
== ﻩﺪﺸﻧ ﺮﭘ ﺭﻭﺮﺳ
Shotgun
== ىﺍ ﻪﻤﭼﺎﺳ ﮓﻨﻔﺗ
Show chat
== ﺖﭼ ﻥﺩﺍﺩ ﻥﺎﺸﻧ
Show friends only
== ﻥﺎﺘﺳﻭﺩ ﺶﯾﺎﻤﻧ ﻂﻘﻓ
Show ingame HUD
== ﯼﺯﺎﺑ ﺭﺩ HUD ﻥﺩﺍﺩ ﻥﺎﺸﻧ
Show name plates
== ﻢﺳﺍ ﻥﺩﺍﺩ ﻥﺎﺸﻧ
Show only chat messages from friends
== ﻥﺎﺘﺳﻭﺩ ﯼﺎﻫ ﻡﺎﯿﭘ ﻥﺩﺍﺩ ﻥﺎﺸﻧ ﻂﻘﻓ
Show only supported
== ﺪﻧﻮﺷ ﯽﻣ ﯽﻧﺎﺒﯿﺘﺸﭘ ﻪﻛ ﯽﯾﺎﻫ ﺖﻟﺎﺣ ﺶﯾﺎﻤﻧ ﻂﻘﻓ
Skins
== ﻦﯿﮑﺳﺍ
Sound
== ﺍﺪﺻ
Sound error
== ﺍﺪﺻ ﯼﺎﻄﺧ
Spectate
== ﺎﺷﺎﻤﺗ
Spectate next
== ﯼﺪﻌﺑ ﯼ ﺎﺷﺎﻤﺗ
Spectate previous
== ﯽﻠﺒﻗ ﯼ ﺎﺷﺎﻤﺗ
Spectator mode
== ﺮﮔﺎﺷﺎﻤﺗ ﺖﻟﺎﺣ
Spectators
== ﺮﮔﺎﺷﺎﻤﺗ
Standard gametype
== ﯼﺯﺎﺑ ﺩﺭﺍﺪﻧﺎﺘﺳﺍ ﯼﺎﻫ ﻝﺪﻣ
Standard map
== ﺩﺭﺍﺪﻧﺎﺘﺳﺍ ﯼﺎﻫ ﭗﻣ
Stop record
== ﻥﺩﺮﮐ ﻂﺒﺿ ﻒﻗﻮﺗ
Strict gametype filter
== ﯼﺯﺎﺑ ﺩﻮﻣ ﺮﺘﻠﯿﻓ
Sudden Death
== ﯽﻧﺎﻬﮔﺎﻧ ﮒﺮﻣ
Switch weapon on pickup
== ﻥﺪﺷ ﻪﺘﺷﺍﺩﺭﻭ ﺕﺭﻮﺻ ﺭﺩ ﻪﺤﻠﺳﺍ ﺮﯿﯿﻐﺗ
Team
== ﻢﯿﺗ
Team chat
== ﻢﯿﺗ ﺖﭼ
The audio device couldn't be initialised.
== .ﺪﺸﻧ ﻥﺪﺷ ﺐﺼﻧ ﻪﺑ ﻖﻓﻮﻣ ﺍﺪﺻ ﻩﺎﮕﺘﺳﺩ
The server is running a non-standard tuning on a pure game type.
== .ﺖﺳﺍ ﺮﮕﯾﺩ ﯼﺯﺎﺑ ﻝﺪﻣ ﮏﯾ ﯼﻭﺭ ﻭ ﺩﺭﺍﺪﻧﺎﺘﺳﺍ ﺮﯿﻏ ﺕﺎﻤﯿﻈﻨﺗ ﯼﺍﺭﺍﺩ ﺍﺮﺟﺍ ﻝﺎﺣ ﺭﺩ ﺭﻭﺮﺳ
There's an unsaved map in the editor, you might want to save it before you quit the game.
== .ﯼﺯﺎﺑ ﺯﺍ ﺝﻭﺮﺧ ﺯﺍ ﻼﺒﻗ ﺪﯿﻨﮐ ﻩﺮﯿﺧﺫ ﺍﺭ ﻥﺁ ﺪﯿﻫﺍﻮﺨﺑ ﺎﻤﺷ ﺖﺳﺍ ﻦﮑﻤﻣ , ﺮﮕﻨﯾﻭﺪﺗ ﺭﺩ ﻩﺪﺸﻧ ﻩﺮﯿﺧﺫ ﭗﻣ ﻦﯾﺍ
Time limit
== ﻥﺎﻣﺯ ﺖﯾﺎﻬﻧ
Time limit: %d min
== ﻪﻘﯿﻗﺩ d% :ﻥﺎﻣﺯ ﺖﯾﺎﻬﻧ
Try again
== ﻩﺭﺎﺑﻭﺩ ﺵﻼﺗ
Type
== ﻝﺪﻣ
Unable to delete the demo
== ﺩﺮﮐ ﮎﺎﭘ ﺍﺭ ﻮﻣﺩ ﻦﯾﺍ ﻥﺍﻮﺘﯿﻤﻧ
Unable to rename the demo
== ﺩﺮﮐ ﺽﻮﻋ ﺍﺭ ﻮﻣﺩ ﻦﯾﺍ ﻢﺳﺍ ﻥﺍﻮﺘﯿﻤﻧ
Use sounds
== ﺍﺪﺻ ﺯﺍ ﻩﺩﺎﻔﺘﺳﺍ
Use team colors for name plates
== ﻢﺳﺍ ﯼﺍﺮﺑ ﻢﯿﺗ ﮓﻧﺭ ﺯﺍ ﻩﺩﺎﻔﺘﺳﺍ
V-Sync
== V-Sync
Version
== ﻪﺨﺴﻧ
Vote command:
== ﯽﺠﻨﺳ ﺮﻈﻧ ﺕﺍﺭﻮﺘﺳﺩ:
Vote description:
== :ﯽﺠﻨﺳ ﺮﻈﻧ ﺕﺎﺤﯿﺿﻮﺗ
Vote no
== ﻪﻧ ﯼﺍﺭ
Vote yes
== ﻪﻠﺑ ﯼﺍﺭ
Voting
== ﯼﺮﯿﮔ ﯼﺍﺭ
Warmup
== ﺪﯿﻨﮐ ﻪﻠﺠﻋ
Weapon
== ﻪﺤﻠﺳﺍ
Yes
== ﻪﻠﺑ
You must restart the game for all settings to take effect.
== ﺪﻧﻮﺷ ﻡﺎﺠﻧﺍ ﺕﺎﻤﯿﻈﻨﺗ ﻪﮑﻨﯾﺍ ﯼﺍﺮﺑ ﺪﯿﻨﮐ ﯼﺭﺍﺰﮔﺭﺎﺑ ﻩﺭﺎﺑﻭﺩ ﺍﺭ ﯼﺯﺎﺑ ﺪﯾﺎﺑ ﺎﻤﺷ
##### ﻪﻤﺟﺮﺗ ﻪﺑ ﺝﺎﯿﺘﺣﺍ #####
Borderless window Borderless window
== ﺯﺮﻣ ﻩﺮﺠﻨﭘ == ﺯﺮﻣ ﻩﺮﺠﻨﭘ
Demo Demo
@ -786,24 +638,231 @@ The width or height of texture %s is not divisible by 16, which might cause visu
Warning Warning
== ==
Team
==
Sudden Death
==
Warmup
==
Please balance teams!
==
Reason:
==
Vote yes
==
Vote no
==
Spectate
==
Menu Menu
== ==
Players
==
Server info
==
The server is running a non-standard tuning on a pure game type.
==
Rename demo
==
Remove friend
==
Sound error
==
The audio device couldn't be initialised.
==
Try again
==
Quit
==
Use k key to kill (restart), q to pause and watch other players. See settings for other key binds. Use k key to kill (restart), q to pause and watch other players. See settings for other key binds.
== ==
There's an unsaved map in the editor, you might want to save it before you quit the game.
==
Yes
==
Country / Region Country / Region
== ==
Unable to delete the demo
==
Unable to rename the demo
==
Show chat
==
Use sounds
==
Speed Speed
== ==
Show ingame HUD
==
Type
==
Refreshing master servers
==
Server filter
==
Server not full
==
Show friends only
==
Standard gametype
==
Standard map
==
Strict gametype filter
==
Server address:
==
Player country:
==
Reset filter
==
Server details
==
Scoreboard
==
Remove
==
Refresh
==
Rename
==
Stop record
==
Player options
==
Player
==
Version
==
Score limit
==
Time limit
==
Vote description:
==
Vote command:
==
Switch weapon on pickup
==
Show only chat messages from friends
==
Show name plates
==
Use team colors for name plates
==
Skip the main menu Skip the main menu
== ==
Skins
==
Shotgun
==
Prev. weapon
==
Team chat
==
Spectator mode
==
Spectate next
==
Spectate previous
==
Remote console
==
Screenshot
==
Weapon
==
Voting
==
Show only supported
==
V-Sync
==
may cause delay may cause delay
== ==
Play background music
==
Sample rate
==
Sound
==
You must restart the game for all settings to take effect.
==
Client message Client message
== ==
@ -830,3 +889,22 @@ Server executable not found, can't run server
Editor Editor
== ==
[Start menu]
Play
==
Time limit: %d min
==
Spectators
==
Score
==
Red team wins!
==
Red team
==

View file

@ -312,6 +312,7 @@ Ping
Pistol Pistol
== Pistolet == Pistolet
[Demo browser]
Play Play
== Graj == Graj
@ -1228,3 +1229,7 @@ Server executable not found, can't run server
Editor Editor
== ==
[Start menu]
Play
==

View file

@ -322,6 +322,7 @@ Ping
Pistol Pistol
== Pistola == Pistola
[Demo browser]
Play Play
== Ver == Ver
@ -1174,6 +1175,10 @@ Server executable not found, can't run server
Editor Editor
== ==
[Start menu]
Play
==
DDNet %s is out! DDNet %s is out!
== ==

View file

@ -316,6 +316,7 @@ Ping
Pistol Pistol
== Pistol == Pistol
[Demo browser]
Play Play
== Redă == Redă
@ -1164,6 +1165,10 @@ Server executable not found, can't run server
Editor Editor
== ==
[Start menu]
Play
==
DDNet %s is out! DDNet %s is out!
== ==

View file

@ -314,6 +314,7 @@ Ping
Pistol Pistol
== Пистолет == Пистолет
[Demo browser]
Play Play
== Просмотр == Просмотр

View file

@ -310,6 +310,7 @@ Ping
Pistol Pistol
== Pištolj == Pištolj
[Demo browser]
Play Play
== Pokreni == Pokreni
@ -1159,6 +1160,10 @@ Server executable not found, can't run server
Editor Editor
== ==
[Start menu]
Play
==
DDNet %s is out! DDNet %s is out!
== ==

View file

@ -341,6 +341,7 @@ Ping
Pistol Pistol
== 手枪 == 手枪
[Demo browser]
Play Play
== 播放 == 播放
@ -1234,3 +1235,7 @@ Server executable not found, can't run server
Editor Editor
== ==
[Start menu]
Play
==

View file

@ -307,6 +307,7 @@ Ping
Pistol Pistol
== Pištoľ == Pištoľ
[Demo browser]
Play Play
== Prehrať == Prehrať
@ -1158,6 +1159,10 @@ Server executable not found, can't run server
Editor Editor
== ==
[Start menu]
Play
==
DDNet %s is out! DDNet %s is out!
== ==

View file

@ -316,6 +316,7 @@ Ping
Pistol Pistol
== Pistola == Pistola
[Demo browser]
Play Play
== Reproducir == Reproducir
@ -1229,3 +1230,7 @@ Server executable not found, can't run server
Editor Editor
== ==
[Start menu]
Play
==

View file

@ -309,6 +309,7 @@ Ping
Pistol Pistol
== Pistol == Pistol
[Demo browser]
Play Play
== Spela == Spela
@ -1225,3 +1226,7 @@ Server executable not found, can't run server
Editor Editor
== ==
[Start menu]
Play
==

View file

@ -335,6 +335,7 @@ Ping
Pistol Pistol
== 手槍 == 手槍
[Demo browser]
Play Play
== 播放 == 播放
@ -1228,3 +1229,7 @@ Server executable not found, can't run server
Editor Editor
== ==
[Start menu]
Play
==

View file

@ -312,6 +312,7 @@ Ping
Pistol Pistol
== Tabanca == Tabanca
[Demo browser]
Play Play
== Oynat == Oynat
@ -1228,3 +1229,7 @@ Server executable not found, can't run server
Editor Editor
== ==
[Start menu]
Play
==

View file

@ -238,6 +238,7 @@ Ping
Pistol Pistol
== Пістолет == Пістолет
[Demo browser]
Play Play
== Перегляд == Перегляд
@ -1223,3 +1224,7 @@ Server executable not found, can't run server
Editor Editor
== ==
[Start menu]
Play
==

View file

@ -48,7 +48,9 @@ if append_missing:
if content[-1] != "\n": if content[-1] != "\n":
content.append("\n") content.append("\n")
for i, miss in enumerate(missing): for i, miss in enumerate(missing):
content.append(local[miss]+"\n== \n\n") if local[miss][1] != "":
content.append("["+local[miss][1]+"]\n")
content.append(local[miss][0]+"\n== \n\n")
content[-1] = content[-1][:-1] content[-1] = content[-1][:-1]
open(outfile, "w").write("".join(content)) open(outfile, "w").write("".join(content))

View file

@ -10,15 +10,23 @@ class LanguageDecodeError(Exception):
def decode(fileobj, elements_per_key): def decode(fileobj, elements_per_key):
data = {} data = {}
current_context = ""
current_key = None current_key = None
for index, line in enumerate(fileobj): for index, line in enumerate(fileobj):
line = line.encode("utf-8").decode("utf-8-sig") line = line.encode("utf-8").decode("utf-8-sig")
line = line[:-1] line = line[:-1]
context = ""
if line and line[-1] == "\r": if line and line[-1] == "\r":
line = line[:-1] line = line[:-1]
if not line or line[:1] == "#": if not line or line[:1] == "#":
current_context = ""
continue continue
if line[:3] == "== ":
if line[0] == "[":
if line[-1] != "]":
raise LanguageDecodeError("Invalid context string", fileobj.name, index)
current_context = line[1:-1]
elif line[:3] == "== ":
if len(data[current_key]) >= 1+elements_per_key: if len(data[current_key]) >= 1+elements_per_key:
raise LanguageDecodeError("Wrong number of elements per key", fileobj.name, index) raise LanguageDecodeError("Wrong number of elements per key", fileobj.name, index)
if current_key: if current_key:
@ -32,8 +40,8 @@ def decode(fileobj, elements_per_key):
data[current_key].append(index) data[current_key].append(index)
if line in data: if line in data:
raise LanguageDecodeError("Key defined multiple times: " + line, fileobj.name, index) raise LanguageDecodeError("Key defined multiple times: " + line, fileobj.name, index)
data[line] = [index] data[(line, current_context)] = [index]
current_key = line current_key = (line, current_context)
if len(data[current_key]) != 1+elements_per_key: if len(data[current_key]) != 1+elements_per_key:
raise LanguageDecodeError("Wrong number of elements per key", fileobj.name, index) raise LanguageDecodeError("Wrong number of elements per key", fileobj.name, index)
data[current_key].append(index+1) data[current_key].append(index+1)
@ -42,7 +50,7 @@ def decode(fileobj, elements_per_key):
def check_file(path): def check_file(path):
with open(path) as fileobj: with open(path) as fileobj:
matches = re.findall("Localize\s*\(\s*\"([^\"]+)\"\s*\)", fileobj.read()) matches = re.findall("Localize\s*\(\s*\"([^\"]+)\"(?:\s*,\s*\"([^\"]+)\")?\s*\)", fileobj.read())
return matches return matches

View file

@ -1245,7 +1245,7 @@ void CMenus::RenderDemoList(CUIRect MainView)
} }
static int s_PlayButton = 0; static int s_PlayButton = 0;
if(DoButton_Menu(&s_PlayButton, m_DemolistSelectedIsDir?Localize("Open"):Localize("Play"), 0, &PlayRect) || Activated || Input()->KeyPress(KEY_P)) if(DoButton_Menu(&s_PlayButton, m_DemolistSelectedIsDir ? Localize("Open") : Localize("Play", "Demo browser"), 0, &PlayRect) || Activated || Input()->KeyPress(KEY_P))
{ {
if(m_DemolistSelectedIndex >= 0) if(m_DemolistSelectedIndex >= 0)
{ {

View file

@ -155,7 +155,7 @@ void CMenus::RenderStartMenu(CUIRect MainView)
Menu.HSplitBottom(5.0f, &Menu, 0); // little space Menu.HSplitBottom(5.0f, &Menu, 0); // little space
Menu.HSplitBottom(40.0f, &Menu, &Button); Menu.HSplitBottom(40.0f, &Menu, &Button);
static int s_PlayButton; static int s_PlayButton;
if(DoButton_Menu(&s_PlayButton, Localize("Play"), 0, &Button, g_Config.m_ClShowStartMenuImages ? "play_game" : 0, CUI::CORNER_ALL, Rounding, 0.5f, vec4(0.0f, 0.0f, 0.0f, 0.5f), vec4(0.0f, 0.0f, 0.0f, 0.25f)) || m_EnterPressed || CheckHotKey(KEY_P)) if(DoButton_Menu(&s_PlayButton, Localize("Play", "Start menu"), 0, &Button, g_Config.m_ClShowStartMenuImages ? "play_game" : 0, CUI::CORNER_ALL, Rounding, 0.5f, vec4(0.0f, 0.0f, 0.0f, 0.5f), vec4(0.0f, 0.0f, 0.0f, 0.25f)) || m_EnterPressed || CheckHotKey(KEY_P))
{ {
NewPage = g_Config.m_UiPage >= PAGE_INTERNET && g_Config.m_UiPage <= PAGE_KOG ? g_Config.m_UiPage : PAGE_DDNET; NewPage = g_Config.m_UiPage >= PAGE_INTERNET && g_Config.m_UiPage <= PAGE_KOG ? g_Config.m_UiPage : PAGE_DDNET;
} }

View file

@ -8,13 +8,13 @@
#include <engine/console.h> #include <engine/console.h>
#include <engine/storage.h> #include <engine/storage.h>
const char *Localize(const char *pStr) const char *Localize(const char *pStr, const char *pContext)
{ {
const char *pNewStr = g_Localization.FindString(str_quickhash(pStr)); const char *pNewStr = g_Localization.FindString(str_quickhash(pStr), str_quickhash(pContext));
return pNewStr ? pNewStr : pStr; return pNewStr ? pNewStr : pStr;
} }
CLocConstString::CLocConstString(const char *pStr) CLocConstString::CLocConstString(const char *pStr, const char *pContext)
{ {
m_pDefaultStr = pStr; m_pDefaultStr = pStr;
m_Hash = str_quickhash(m_pDefaultStr); m_Hash = str_quickhash(m_pDefaultStr);
@ -24,7 +24,7 @@ CLocConstString::CLocConstString(const char *pStr)
void CLocConstString::Reload() void CLocConstString::Reload()
{ {
m_Version = g_Localization.Version(); m_Version = g_Localization.Version();
const char *pNewStr = g_Localization.FindString(m_Hash); const char *pNewStr = g_Localization.FindString(m_Hash, m_ContextHash);
m_pCurrentStr = pNewStr; m_pCurrentStr = pNewStr;
if(!m_pCurrentStr) if(!m_pCurrentStr)
m_pCurrentStr = m_pDefaultStr; m_pCurrentStr = m_pDefaultStr;
@ -36,10 +36,11 @@ CLocalizationDatabase::CLocalizationDatabase()
m_CurrentVersion = 0; m_CurrentVersion = 0;
} }
void CLocalizationDatabase::AddString(const char *pOrgStr, const char *pNewStr) void CLocalizationDatabase::AddString(const char *pOrgStr, const char *pNewStr, const char *pContext)
{ {
CString s; CString s;
s.m_Hash = str_quickhash(pOrgStr); s.m_Hash = str_quickhash(pOrgStr);
s.m_ContextHash = str_quickhash(pContext);
s.m_Replacement = *pNewStr ? pNewStr : pOrgStr; s.m_Replacement = *pNewStr ? pNewStr : pOrgStr;
m_Strings.add(s); m_Strings.add(s);
} }
@ -63,6 +64,7 @@ bool CLocalizationDatabase::Load(const char *pFilename, IStorage *pStorage, ICon
pConsole->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "localization", aBuf); pConsole->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "localization", aBuf);
m_Strings.clear(); m_Strings.clear();
char aContext[512];
char aOrigin[512]; char aOrigin[512];
CLineReader LineReader; CLineReader LineReader;
LineReader.Init(IoHandle); LineReader.Init(IoHandle);
@ -77,6 +79,23 @@ bool CLocalizationDatabase::Load(const char *pFilename, IStorage *pStorage, ICon
if(pLine[0] == '#') // skip comments if(pLine[0] == '#') // skip comments
continue; continue;
if(pLine[0] == '[') // context
{
size_t Len = str_length(pLine);
if(Len < 1 || pLine[Len - 1] != ']')
{
str_format(aBuf, sizeof(aBuf), "malform context line (%d): %s", Line, pLine);
pConsole->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "localization", aBuf);
continue;
}
str_copy(aContext, pLine + 1, Len - 1);
pLine = LineReader.Get();
}
else
{
aContext[0] = '\0';
}
str_copy(aOrigin, pLine, sizeof(aOrigin)); str_copy(aOrigin, pLine, sizeof(aOrigin));
char *pReplacement = LineReader.Get(); char *pReplacement = LineReader.Get();
Line++; Line++;
@ -94,7 +113,7 @@ bool CLocalizationDatabase::Load(const char *pFilename, IStorage *pStorage, ICon
} }
pReplacement += 3; pReplacement += 3;
AddString(aOrigin, pReplacement); AddString(aOrigin, pReplacement, aContext);
} }
io_close(IoHandle); io_close(IoHandle);
@ -102,14 +121,27 @@ bool CLocalizationDatabase::Load(const char *pFilename, IStorage *pStorage, ICon
return true; return true;
} }
const char *CLocalizationDatabase::FindString(unsigned Hash) const char *CLocalizationDatabase::FindString(unsigned Hash, unsigned ContextHash)
{ {
CString String; CString String;
String.m_Hash = Hash; String.m_Hash = Hash;
String.m_ContextHash = ContextHash;
sorted_array<CString>::range r = ::find_binary(m_Strings.all(), String); sorted_array<CString>::range r = ::find_binary(m_Strings.all(), String);
if(r.empty()) if(r.empty())
return 0; return 0;
return r.front().m_Replacement;
unsigned DefaultHash = str_quickhash("");
unsigned DefaultIndex = 0;
for(unsigned i = 0; i < r.size() && r.index(i).m_Hash == Hash; ++i)
{
const CString &rStr = r.index(i);
if(rStr.m_ContextHash == ContextHash)
return rStr.m_Replacement;
else if(rStr.m_ContextHash == DefaultHash)
DefaultIndex = i;
}
return r.index(DefaultIndex).m_Replacement;
} }
CLocalizationDatabase g_Localization; CLocalizationDatabase g_Localization;

View file

@ -11,13 +11,14 @@ class CLocalizationDatabase
{ {
public: public:
unsigned m_Hash; unsigned m_Hash;
unsigned m_ContextHash;
// TODO: do this as an const char * and put everything on a incremental heap // TODO: do this as an const char * and put everything on a incremental heap
string m_Replacement; string m_Replacement;
bool operator <(const CString &Other) const { return m_Hash < Other.m_Hash; } bool operator<(const CString &Other) const { return m_Hash < Other.m_Hash || (m_Hash == Other.m_Hash && m_ContextHash < Other.m_ContextHash); }
bool operator <=(const CString &Other) const { return m_Hash <= Other.m_Hash; } bool operator<=(const CString &Other) const { return m_Hash < Other.m_Hash || (m_Hash == Other.m_Hash && m_ContextHash <= Other.m_ContextHash); }
bool operator ==(const CString &Other) const { return m_Hash == Other.m_Hash; } bool operator==(const CString &Other) const { return m_Hash == Other.m_Hash && m_ContextHash == Other.m_ContextHash; }
}; };
sorted_array<CString> m_Strings; sorted_array<CString> m_Strings;
@ -31,8 +32,8 @@ public:
int Version() { return m_CurrentVersion; } int Version() { return m_CurrentVersion; }
void AddString(const char *pOrgStr, const char *pNewStr); void AddString(const char *pOrgStr, const char *pNewStr, const char *pContext);
const char *FindString(unsigned Hash); const char *FindString(unsigned Hash, unsigned ContextHash);
}; };
extern CLocalizationDatabase g_Localization; extern CLocalizationDatabase g_Localization;
@ -42,9 +43,11 @@ class CLocConstString
const char *m_pDefaultStr; const char *m_pDefaultStr;
const char *m_pCurrentStr; const char *m_pCurrentStr;
unsigned m_Hash; unsigned m_Hash;
unsigned m_ContextHash;
int m_Version; int m_Version;
public: public:
CLocConstString(const char *pStr); CLocConstString(const char *pStr, const char *pContext = "");
void Reload(); void Reload();
inline operator const char *() inline operator const char *()
@ -55,7 +58,6 @@ public:
} }
}; };
extern const char *Localize(const char *pStr, const char *pContext = "")
extern const char *Localize(const char *pStr) GNUC_ATTRIBUTE((format_arg(1)));
GNUC_ATTRIBUTE((format_arg(1)));
#endif #endif