[i18n] add language changing at runtime in webconsole

Signed-off-by: R4SAS <r4sas@i2pmail.org>
This commit is contained in:
R4SAS 2021-06-27 17:14:45 +03:00
parent 6d2c9e367b
commit 12d6f03dc9
No known key found for this signature in database
GPG Key ID: 66F6C87B98EBCFE2
9 changed files with 396 additions and 354 deletions

View File

@ -26,548 +26,554 @@ msgstr ""
msgid "Enabled" msgid "Enabled"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:141 #: daemon/HTTPServer.cpp:147
msgid "day" msgid "day"
msgid_plural "days" msgid_plural "days"
msgstr[0] "" msgstr[0] ""
msgstr[1] "" msgstr[1] ""
#: daemon/HTTPServer.cpp:145
#: daemon/HTTPServer.cpp:151
msgid "hour" msgid "hour"
msgid_plural "hours" msgid_plural "hours"
msgstr[0] "" msgstr[0] ""
msgstr[1] "" msgstr[1] ""
#: daemon/HTTPServer.cpp:149
#: daemon/HTTPServer.cpp:155
msgid "minute" msgid "minute"
msgid_plural "minutes" msgid_plural "minutes"
msgstr[0] "" msgstr[0] ""
msgstr[1] "" msgstr[1] ""
#: daemon/HTTPServer.cpp:152 #: daemon/HTTPServer.cpp:158
msgid "second" msgid "second"
msgid_plural "seconds" msgid_plural "seconds"
msgstr[0] "" msgstr[0] ""
msgstr[1] "" msgstr[1] ""
#: daemon/HTTPServer.cpp:160 daemon/HTTPServer.cpp:188 #: daemon/HTTPServer.cpp:166 daemon/HTTPServer.cpp:194
msgid "KiB" msgid "KiB"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:162 #: daemon/HTTPServer.cpp:168
msgid "MiB" msgid "MiB"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:164 #: daemon/HTTPServer.cpp:170
msgid "GiB" msgid "GiB"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:181 #: daemon/HTTPServer.cpp:187
msgid "building" msgid "building"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:182 #: daemon/HTTPServer.cpp:188
msgid "failed" msgid "failed"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:183 #: daemon/HTTPServer.cpp:189
msgid "expiring" msgid "expiring"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:184 #: daemon/HTTPServer.cpp:190
msgid "established" msgid "established"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:185 #: daemon/HTTPServer.cpp:191
msgid "unknown" msgid "unknown"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:187 #: daemon/HTTPServer.cpp:193
msgid "exploratory" msgid "exploratory"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:223 #: daemon/HTTPServer.cpp:229
msgid "<b>i2pd</b> webconsole" msgid "<b>i2pd</b> webconsole"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:226 #: daemon/HTTPServer.cpp:232
msgid "Main page" msgid "Main page"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:227 daemon/HTTPServer.cpp:683 #: daemon/HTTPServer.cpp:233 daemon/HTTPServer.cpp:689
msgid "Router commands" msgid "Router commands"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:228 #: daemon/HTTPServer.cpp:234
msgid "Local destinations" msgid "Local destinations"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:230 daemon/HTTPServer.cpp:382 #: daemon/HTTPServer.cpp:236 daemon/HTTPServer.cpp:388
#: daemon/HTTPServer.cpp:463 daemon/HTTPServer.cpp:469 #: daemon/HTTPServer.cpp:469 daemon/HTTPServer.cpp:475
#: daemon/HTTPServer.cpp:599 daemon/HTTPServer.cpp:642 #: daemon/HTTPServer.cpp:605 daemon/HTTPServer.cpp:648
#: daemon/HTTPServer.cpp:646 #: daemon/HTTPServer.cpp:652
msgid "LeaseSets" msgid "LeaseSets"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:232 daemon/HTTPServer.cpp:652 #: daemon/HTTPServer.cpp:238 daemon/HTTPServer.cpp:658
msgid "Tunnels" msgid "Tunnels"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:233 daemon/HTTPServer.cpp:727 #: daemon/HTTPServer.cpp:239 daemon/HTTPServer.cpp:746
#: daemon/HTTPServer.cpp:743 #: daemon/HTTPServer.cpp:762
msgid "Transit tunnels" msgid "Transit tunnels"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:234 daemon/HTTPServer.cpp:792 #: daemon/HTTPServer.cpp:240 daemon/HTTPServer.cpp:811
msgid "Transports" msgid "Transports"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:235 #: daemon/HTTPServer.cpp:241
msgid "I2P tunnels" msgid "I2P tunnels"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:237 daemon/HTTPServer.cpp:854 #: daemon/HTTPServer.cpp:243 daemon/HTTPServer.cpp:873
#: daemon/HTTPServer.cpp:864 #: daemon/HTTPServer.cpp:883
msgid "SAM sessions" msgid "SAM sessions"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:253 daemon/HTTPServer.cpp:1254 #: daemon/HTTPServer.cpp:259 daemon/HTTPServer.cpp:1273
#: daemon/HTTPServer.cpp:1257 daemon/HTTPServer.cpp:1260 #: daemon/HTTPServer.cpp:1276 daemon/HTTPServer.cpp:1279
#: daemon/HTTPServer.cpp:1274 daemon/HTTPServer.cpp:1319 #: daemon/HTTPServer.cpp:1293 daemon/HTTPServer.cpp:1338
#: daemon/HTTPServer.cpp:1322 daemon/HTTPServer.cpp:1325 #: daemon/HTTPServer.cpp:1341 daemon/HTTPServer.cpp:1344
msgid "ERROR" msgid "ERROR"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:260 #: daemon/HTTPServer.cpp:266
msgid "OK" msgid "OK"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:261 #: daemon/HTTPServer.cpp:267
msgid "Testing" msgid "Testing"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:262 #: daemon/HTTPServer.cpp:268
msgid "Firewalled" msgid "Firewalled"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:263 daemon/HTTPServer.cpp:284 #: daemon/HTTPServer.cpp:269 daemon/HTTPServer.cpp:290
#: daemon/HTTPServer.cpp:370 #: daemon/HTTPServer.cpp:376
msgid "Unknown" msgid "Unknown"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:264 daemon/HTTPServer.cpp:394 #: daemon/HTTPServer.cpp:270 daemon/HTTPServer.cpp:400
#: daemon/HTTPServer.cpp:395 daemon/HTTPServer.cpp:922 #: daemon/HTTPServer.cpp:401 daemon/HTTPServer.cpp:941
#: daemon/HTTPServer.cpp:931 #: daemon/HTTPServer.cpp:950
msgid "Proxy" msgid "Proxy"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:265 #: daemon/HTTPServer.cpp:271
msgid "Mesh" msgid "Mesh"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:268 #: daemon/HTTPServer.cpp:274
msgid "Error" msgid "Error"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:272 #: daemon/HTTPServer.cpp:278
msgid "Clock skew" msgid "Clock skew"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:275 #: daemon/HTTPServer.cpp:281
msgid "Offline" msgid "Offline"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:278 #: daemon/HTTPServer.cpp:284
msgid "Symmetric NAT" msgid "Symmetric NAT"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:290 #: daemon/HTTPServer.cpp:296
msgid "Uptime" msgid "Uptime"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:293 #: daemon/HTTPServer.cpp:299
msgid "Network status" msgid "Network status"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:298 #: daemon/HTTPServer.cpp:304
msgid "Network status v6" msgid "Network status v6"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:304 daemon/HTTPServer.cpp:311 #: daemon/HTTPServer.cpp:310 daemon/HTTPServer.cpp:317
msgid "Stopping in" msgid "Stopping in"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:318 #: daemon/HTTPServer.cpp:324
msgid "Family" msgid "Family"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:319 #: daemon/HTTPServer.cpp:325
msgid "Tunnel creation success rate" msgid "Tunnel creation success rate"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:320 #: daemon/HTTPServer.cpp:326
msgid "Received" msgid "Received"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:322 daemon/HTTPServer.cpp:325 #: daemon/HTTPServer.cpp:328 daemon/HTTPServer.cpp:331
#: daemon/HTTPServer.cpp:328 #: daemon/HTTPServer.cpp:334
msgid "KiB/s" msgid "KiB/s"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:323 #: daemon/HTTPServer.cpp:329
msgid "Sent" msgid "Sent"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:326 #: daemon/HTTPServer.cpp:332
msgid "Transit" msgid "Transit"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:329 #: daemon/HTTPServer.cpp:335
msgid "Data path" msgid "Data path"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:332 #: daemon/HTTPServer.cpp:338
msgid "Hidden content. Press on text to see." msgid "Hidden content. Press on text to see."
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:335 #: daemon/HTTPServer.cpp:341
msgid "Router Ident" msgid "Router Ident"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:337 #: daemon/HTTPServer.cpp:343
msgid "Router Family" msgid "Router Family"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:338 #: daemon/HTTPServer.cpp:344
msgid "Router Caps" msgid "Router Caps"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:339 #: daemon/HTTPServer.cpp:345
msgid "Version" msgid "Version"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:340 #: daemon/HTTPServer.cpp:346
msgid "Our external address" msgid "Our external address"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:348 #: daemon/HTTPServer.cpp:354
msgid "supported" msgid "supported"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:380 #: daemon/HTTPServer.cpp:386
msgid "Routers" msgid "Routers"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:381 #: daemon/HTTPServer.cpp:387
msgid "Floodfills" msgid "Floodfills"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:388 daemon/HTTPServer.cpp:908 #: daemon/HTTPServer.cpp:394 daemon/HTTPServer.cpp:927
msgid "Client Tunnels" msgid "Client Tunnels"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:389 #: daemon/HTTPServer.cpp:395
msgid "Transit Tunnels" msgid "Transit Tunnels"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:393 #: daemon/HTTPServer.cpp:399
msgid "Services" msgid "Services"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:407 daemon/HTTPServer.cpp:419 #: daemon/HTTPServer.cpp:413 daemon/HTTPServer.cpp:425
msgid "Local Destinations" msgid "Local Destinations"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:442 #: daemon/HTTPServer.cpp:448
msgid "Encrypted B33 address" msgid "Encrypted B33 address"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:451 #: daemon/HTTPServer.cpp:457
msgid "Address registration line" msgid "Address registration line"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:456 #: daemon/HTTPServer.cpp:462
msgid "Domain" msgid "Domain"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:457 #: daemon/HTTPServer.cpp:463
msgid "Generate" msgid "Generate"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:458 #: daemon/HTTPServer.cpp:464
msgid "" msgid ""
"<b>Note:</b> result string can be used only for registering 2LD domains " "<b>Note:</b> result string can be used only for registering 2LD domains "
"(example.i2p). For registering subdomains please use i2pd-tools." "(example.i2p). For registering subdomains please use i2pd-tools."
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:464 #: daemon/HTTPServer.cpp:470
msgid "Address" msgid "Address"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:464 #: daemon/HTTPServer.cpp:470
msgid "Type" msgid "Type"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:464 #: daemon/HTTPServer.cpp:470
msgid "EncType" msgid "EncType"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:474 daemon/HTTPServer.cpp:657 #: daemon/HTTPServer.cpp:480 daemon/HTTPServer.cpp:663
msgid "Inbound tunnels" msgid "Inbound tunnels"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:479 daemon/HTTPServer.cpp:489 #. Milliseconds
#: daemon/HTTPServer.cpp:662 daemon/HTTPServer.cpp:672 #: daemon/HTTPServer.cpp:485 daemon/HTTPServer.cpp:495
#: Means milliseconds #: daemon/HTTPServer.cpp:668 daemon/HTTPServer.cpp:678
msgid "ms" msgid "ms"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:484 daemon/HTTPServer.cpp:667 #: daemon/HTTPServer.cpp:490 daemon/HTTPServer.cpp:673
msgid "Outbound tunnels" msgid "Outbound tunnels"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:496 #: daemon/HTTPServer.cpp:502
msgid "Tags" msgid "Tags"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:496 #: daemon/HTTPServer.cpp:502
msgid "Incoming" msgid "Incoming"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:503 daemon/HTTPServer.cpp:506 #: daemon/HTTPServer.cpp:509 daemon/HTTPServer.cpp:512
msgid "Outgoing" msgid "Outgoing"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:504 daemon/HTTPServer.cpp:520 #: daemon/HTTPServer.cpp:510 daemon/HTTPServer.cpp:526
msgid "Destination" msgid "Destination"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:504 #: daemon/HTTPServer.cpp:510
msgid "Amount" msgid "Amount"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:511 #: daemon/HTTPServer.cpp:517
msgid "Incoming Tags" msgid "Incoming Tags"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:519 daemon/HTTPServer.cpp:522 #: daemon/HTTPServer.cpp:525 daemon/HTTPServer.cpp:528
msgid "Tags sessions" msgid "Tags sessions"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:520 #: daemon/HTTPServer.cpp:526
msgid "Status" msgid "Status"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:529 daemon/HTTPServer.cpp:584 #: daemon/HTTPServer.cpp:535 daemon/HTTPServer.cpp:590
msgid "Local Destination" msgid "Local Destination"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:538 daemon/HTTPServer.cpp:887 #: daemon/HTTPServer.cpp:544 daemon/HTTPServer.cpp:906
msgid "Streams" msgid "Streams"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:560 #: daemon/HTTPServer.cpp:566
msgid "Close stream" msgid "Close stream"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:589 #: daemon/HTTPServer.cpp:595
msgid "I2CP session not found" msgid "I2CP session not found"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:592 #: daemon/HTTPServer.cpp:598
msgid "I2CP is not enabled" msgid "I2CP is not enabled"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:618 #: daemon/HTTPServer.cpp:624
msgid "Invalid" msgid "Invalid"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:621 #: daemon/HTTPServer.cpp:627
msgid "Store type" msgid "Store type"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:622 #: daemon/HTTPServer.cpp:628
msgid "Expires" msgid "Expires"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:627 #: daemon/HTTPServer.cpp:633
msgid "Non Expired Leases" msgid "Non Expired Leases"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:630 #: daemon/HTTPServer.cpp:636
msgid "Gateway" msgid "Gateway"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:631 #: daemon/HTTPServer.cpp:637
msgid "TunnelID" msgid "TunnelID"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:632 #: daemon/HTTPServer.cpp:638
msgid "EndDate" msgid "EndDate"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:642 #: daemon/HTTPServer.cpp:648
msgid "not floodfill" msgid "not floodfill"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:653 #: daemon/HTTPServer.cpp:659
msgid "Queue size" msgid "Queue size"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:684 #: daemon/HTTPServer.cpp:690
msgid "Run peer test" msgid "Run peer test"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:687 #: daemon/HTTPServer.cpp:693
msgid "Decline transit tunnels" msgid "Decline transit tunnels"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:689 #: daemon/HTTPServer.cpp:695
msgid "Accept transit tunnels" msgid "Accept transit tunnels"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:692 daemon/HTTPServer.cpp:697 #: daemon/HTTPServer.cpp:698 daemon/HTTPServer.cpp:703
msgid "Cancel graceful shutdown" msgid "Cancel graceful shutdown"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:694 daemon/HTTPServer.cpp:699 #: daemon/HTTPServer.cpp:700 daemon/HTTPServer.cpp:705
msgid "Start graceful shutdown" msgid "Start graceful shutdown"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:701 #: daemon/HTTPServer.cpp:707
msgid "Force shutdown" msgid "Force shutdown"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:704 #: daemon/HTTPServer.cpp:710
msgid "" msgid ""
"<b>Note:</b> any action done here are not persistent and not changes your " "<b>Note:</b> any action done here are not persistent and not changes your "
"config files." "config files."
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:706 #: daemon/HTTPServer.cpp:712
msgid "Logging level" msgid "Logging level"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:714 #: daemon/HTTPServer.cpp:720
msgid "Transit tunnels limit" msgid "Transit tunnels limit"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:719 #: daemon/HTTPServer.cpp:725 daemon/HTTPServer.cpp:737
msgid "Change" msgid "Change"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:743 #: daemon/HTTPServer.cpp:729
msgid "Change language"
msgstr ""
#: daemon/HTTPServer.cpp:762
msgid "no transit tunnels currently built" msgid "no transit tunnels currently built"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:848 daemon/HTTPServer.cpp:871 #: daemon/HTTPServer.cpp:867 daemon/HTTPServer.cpp:890
msgid "SAM disabled" msgid "SAM disabled"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:864 #: daemon/HTTPServer.cpp:883
msgid "no sessions currently running" msgid "no sessions currently running"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:877 #: daemon/HTTPServer.cpp:896
msgid "SAM session not found" msgid "SAM session not found"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:882 #: daemon/HTTPServer.cpp:901
msgid "SAM Session" msgid "SAM Session"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:939 #: daemon/HTTPServer.cpp:958
msgid "Server Tunnels" msgid "Server Tunnels"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:955 #: daemon/HTTPServer.cpp:974
msgid "Client Forwards" msgid "Client Forwards"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:969 #: daemon/HTTPServer.cpp:988
msgid "Server Forwards" msgid "Server Forwards"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1175 #: daemon/HTTPServer.cpp:1194
msgid "Unknown page" msgid "Unknown page"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1194 #: daemon/HTTPServer.cpp:1213
msgid "Invalid token" msgid "Invalid token"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1252 daemon/HTTPServer.cpp:1309 #: daemon/HTTPServer.cpp:1271 daemon/HTTPServer.cpp:1328
#: daemon/HTTPServer.cpp:1337 #: daemon/HTTPServer.cpp:1364
msgid "SUCCESS" msgid "SUCCESS"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1252 #: daemon/HTTPServer.cpp:1271
msgid "Stream closed" msgid "Stream closed"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1254 #: daemon/HTTPServer.cpp:1273
msgid "Stream not found or already was closed" msgid "Stream not found or already was closed"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1257 #: daemon/HTTPServer.cpp:1276
msgid "Destination not found" msgid "Destination not found"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1260 #: daemon/HTTPServer.cpp:1279
msgid "StreamID can't be null" msgid "StreamID can't be null"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1262 daemon/HTTPServer.cpp:1327 #: daemon/HTTPServer.cpp:1281 daemon/HTTPServer.cpp:1346
msgid "Return to destination page" msgid "Return to destination page"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1263 daemon/HTTPServer.cpp:1276 #: daemon/HTTPServer.cpp:1282 daemon/HTTPServer.cpp:1295
msgid "You will be redirected back in 5 seconds" msgid "You will be redirected back in 5 seconds"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1274 #: daemon/HTTPServer.cpp:1293
msgid "Transit tunnels count must not exceed 65535" msgid "Transit tunnels count must not exceed 65535"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1275 daemon/HTTPServer.cpp:1338 #: daemon/HTTPServer.cpp:1294 daemon/HTTPServer.cpp:1365
msgid "Back to commands list" msgid "Back to commands list"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1311 #: daemon/HTTPServer.cpp:1330
msgid "Register at reg.i2p" msgid "Register at reg.i2p"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1312 #: daemon/HTTPServer.cpp:1331
msgid "Description" msgid "Description"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1312 #: daemon/HTTPServer.cpp:1331
msgid "A bit information about service on domain" msgid "A bit information about service on domain"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1313 #: daemon/HTTPServer.cpp:1332
msgid "Submit" msgid "Submit"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1319 #: daemon/HTTPServer.cpp:1338
msgid "Domain can't end with .b32.i2p" msgid "Domain can't end with .b32.i2p"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1322 #: daemon/HTTPServer.cpp:1341
msgid "Domain must end with .i2p" msgid "Domain must end with .i2p"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1325 #: daemon/HTTPServer.cpp:1344
msgid "Such destination is not found" msgid "Such destination is not found"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1333 #: daemon/HTTPServer.cpp:1360
msgid "Unknown command" msgid "Unknown command"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1337 #: daemon/HTTPServer.cpp:1364
msgid "Command accepted" msgid "Command accepted"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1339 #: daemon/HTTPServer.cpp:1366
msgid "You will be redirected in 5 seconds" msgid "You will be redirected in 5 seconds"
msgstr "" msgstr ""

View File

@ -68,11 +68,11 @@ namespace http {
<< " a.button { -webkit-appearance: button; -moz-appearance: button; appearance: button; text-decoration: none;\r\n" << " a.button { -webkit-appearance: button; -moz-appearance: button; appearance: button; text-decoration: none;\r\n"
<< " color: initial; padding: 0 5px; border: 1px solid #894C84; }\r\n" << " color: initial; padding: 0 5px; border: 1px solid #894C84; }\r\n"
<< " .header { font-size: 2.5em; text-align: center; margin: 1em 0; color: #894C84; }\r\n" << " .header { font-size: 2.5em; text-align: center; margin: 1em 0; color: #894C84; }\r\n"
<< " .wrapper { margin: 0 auto; padding: 1em; max-width: 58em; }\r\n" << " .wrapper { margin: 0 auto; padding: 1em; max-width: 64em; }\r\n"
<< " .menu { float: left; } .menu a, .commands a { display: block; }\r\n" << " .menu { display: block; float: left; overflow: hidden; max-width: 12em; white-space: nowrap; text-overflow: ellipsis; }\r\n"
<< " .listitem { display: block; font-family: monospace; font-size: 1.2em; white-space: nowrap; }\r\n" << " .listitem { display: block; font-family: monospace; font-size: 1.2em; white-space: nowrap; }\r\n"
<< " .tableitem { font-family: monospace; font-size: 1.2em; white-space: nowrap; }\r\n" << " .tableitem { font-family: monospace; font-size: 1.2em; white-space: nowrap; }\r\n"
<< " .content { float: left; font-size: 1em; margin-left: 4em; max-width: 45em; overflow: auto; }\r\n" << " .content { float: left; font-size: 1em; margin-left: 4em; max-width: 48em; overflow: auto; }\r\n"
<< " .tunnel.established { color: #56B734; } .tunnel.expiring { color: #D3AE3F; }\r\n" << " .tunnel.established { color: #56B734; } .tunnel.expiring { color: #D3AE3F; }\r\n"
<< " .tunnel.failed { color: #D33F3F; } .tunnel.building { color: #434343; }\r\n" << " .tunnel.failed { color: #D33F3F; } .tunnel.building { color: #434343; }\r\n"
<< " caption { font-size: 1.5em; text-align: center; color: #894C84; }\r\n" << " caption { font-size: 1.5em; text-align: center; color: #894C84; }\r\n"
@ -84,19 +84,24 @@ namespace http {
<< " .slide [type=\"checkbox\"]:checked ~ div.slidecontent { display: block; margin-top: 0; padding: 0; }\r\n" << " .slide [type=\"checkbox\"]:checked ~ div.slidecontent { display: block; margin-top: 0; padding: 0; }\r\n"
<< " .disabled:after { color: #D33F3F; content: \"" << tr("Disabled") << "\" }\r\n" << " .disabled:after { color: #D33F3F; content: \"" << tr("Disabled") << "\" }\r\n"
<< " .enabled:after { color: #56B734; content: \"" << tr("Enabled") << "\" }\r\n" << " .enabled:after { color: #56B734; content: \"" << tr("Enabled") << "\" }\r\n"
<< " @media screen and (max-width: 980px) {\r\n" /* adaptive style */ << " @media screen and (max-width: 1150px) {\r\n" /* adaptive style */
<< " .wrapper { max-width: 58em; } .menu { max-width: 10em; }\r\n"
<< " .content { margin-left: 2em; max-width: 42em; }\r\n"
<< " }\r\n"
<< " @media screen and (max-width: 980px) {\r\n"
<< " body { padding: 1.5em 0 0 0; }\r\n" << " body { padding: 1.5em 0 0 0; }\r\n"
<< " .menu { width: 100%; display: block; float: none; position: unset; font-size: 16px;\r\n" << " .menu { width: 100%; max-width: unset; display: block; float: none; position: unset; font-size: 16px;\r\n"
<< " text-align: center; }\r\n" << " text-align: center; }\r\n"
<< " .menu a, .commands a { padding: 2px; }\r\n" << " .menu a, .commands a { display: inline-block; padding: 4px; }\r\n"
<< " .content { float: none; margin-left: unset; margin-top: 16px; max-width: 100%; width: 100%;\r\n" << " .content { float: none; margin-left: unset; margin-top: 16px; max-width: 100%; width: 100%;\r\n"
<< " text-align: center; }\r\n" << " text-align: center; }\r\n"
<< " a, .slide label { /* margin-right: 10px; */ display: block; /* font-size: 18px; */ }\r\n" << " a, .slide label { /* margin-right: 10px; */ display: block; /* font-size: 18px; */ }\r\n"
<< " .header { margin: unset; font-size: 1.5em; } small {display: block}\r\n" << " .header { margin: unset; font-size: 1.5em; } small {display: block}\r\n"
<< " a.button { -webkit-appearance: button; -moz-appearance: button; appearance: button; text-decoration: none;\r\n" << " a.button { -webkit-appearance: button; -moz-appearance: button; appearance: button; text-decoration: none;\r\n"
<< " color: initial; margin-top: 10px; padding: 6px; border: 1px solid #894c84; width: -webkit-fill-available; }\r\n" << " color: initial; margin-top: 10px; padding: 6px; border: 1px solid #894c84; width: -webkit-fill-available; }\r\n"
<< " input { width: 35%; text-align: center; padding: 5px;\r\n" << " input, select { width: 35%; text-align: center; padding: 5px;\r\n"
<< " border: 2px solid #ccc; -webkit-border-radius: 5px; border-radius: 5px; font-size: 18px; }\r\n" << " border: 2px solid #ccc; -webkit-border-radius: 5px; border-radius: 5px; font-size: 18px; }\r\n"
<< " table.extaddr { margin: auto; text-align: unset; }\r\n"
<< " textarea { width: -webkit-fill-available; height: auto; padding:5px; border:2px solid #ccc;\r\n" << " textarea { width: -webkit-fill-available; height: auto; padding:5px; border:2px solid #ccc;\r\n"
<< " -webkit-border-radius: 5px; border-radius: 5px; font-size: 12px; }\r\n" << " -webkit-border-radius: 5px; border-radius: 5px; font-size: 12px; }\r\n"
<< " button[type=submit] { padding: 5px 15px; background: #ccc; border: 0 none; cursor: pointer;\r\n" << " button[type=submit] { padding: 5px 15px; background: #ccc; border: 0 none; cursor: pointer;\r\n"
@ -127,6 +132,7 @@ namespace http {
const char HTTP_COMMAND_KILLSTREAM[] = "closestream"; const char HTTP_COMMAND_KILLSTREAM[] = "closestream";
const char HTTP_COMMAND_LIMITTRANSIT[] = "limittransit"; const char HTTP_COMMAND_LIMITTRANSIT[] = "limittransit";
const char HTTP_COMMAND_GET_REG_STRING[] = "get_reg_string"; const char HTTP_COMMAND_GET_REG_STRING[] = "get_reg_string";
const char HTTP_COMMAND_SETLANGUAGE[] = "setlanguage";
const char HTTP_PARAM_SAM_SESSION_ID[] = "id"; const char HTTP_PARAM_SAM_SESSION_ID[] = "id";
const char HTTP_PARAM_ADDRESS[] = "address"; const char HTTP_PARAM_ADDRESS[] = "address";
@ -223,18 +229,18 @@ namespace http {
"<div class=\"header\">" << tr("<b>i2pd</b> webconsole") << "</div>\r\n" "<div class=\"header\">" << tr("<b>i2pd</b> webconsole") << "</div>\r\n"
"<div class=\"wrapper\">\r\n" "<div class=\"wrapper\">\r\n"
"<div class=\"menu\">\r\n" "<div class=\"menu\">\r\n"
" <a href=\"" << webroot << "\">" << tr("Main page") << "</a><br>\r\n" " <a href=\"" << webroot << "\">" << tr("Main page") << "</a><br><br>\r\n"
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_COMMANDS << "\">" << tr("Router commands") << "</a>\r\n" " <a href=\"" << webroot << "?page=" << HTTP_PAGE_COMMANDS << "\">" << tr("Router commands") << "</a><br>\r\n"
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATIONS << "\">" << tr("Local destinations") << "</a>\r\n"; " <a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATIONS << "\">" << tr("Local destinations") << "</a><br>\r\n";
if (i2p::context.IsFloodfill ()) if (i2p::context.IsFloodfill ())
s << " <a href=\"" << webroot << "?page=" << HTTP_PAGE_LEASESETS << "\">" << tr("LeaseSets") << "</a>\r\n"; s << " <a href=\"" << webroot << "?page=" << HTTP_PAGE_LEASESETS << "\">" << tr("LeaseSets") << "</a><br>\r\n";
s << s <<
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_TUNNELS << "\">" << tr("Tunnels") << "</a>\r\n" " <a href=\"" << webroot << "?page=" << HTTP_PAGE_TUNNELS << "\">" << tr("Tunnels") << "</a><br>\r\n"
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_TRANSIT_TUNNELS << "\">" << tr("Transit tunnels") << "</a>\r\n" " <a href=\"" << webroot << "?page=" << HTTP_PAGE_TRANSIT_TUNNELS << "\">" << tr("Transit tunnels") << "</a><br>\r\n"
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_TRANSPORTS << "\">" << tr ("Transports") << "</a>\r\n" " <a href=\"" << webroot << "?page=" << HTTP_PAGE_TRANSPORTS << "\">" << tr ("Transports") << "</a><br>\r\n"
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_I2P_TUNNELS << "\">" << tr("I2P tunnels") << "</a>\r\n"; " <a href=\"" << webroot << "?page=" << HTTP_PAGE_I2P_TUNNELS << "\">" << tr("I2P tunnels") << "</a><br>\r\n";
if (i2p::client::context.GetSAMBridge ()) if (i2p::client::context.GetSAMBridge ())
s << " <a href=\"" << webroot << "?page=" << HTTP_PAGE_SAM_SESSIONS << "\">" << tr("SAM sessions") << "</a>\r\n"; s << " <a href=\"" << webroot << "?page=" << HTTP_PAGE_SAM_SESSIONS << "\">" << tr("SAM sessions") << "</a><br>\r\n";
s << s <<
"</div>\r\n" "</div>\r\n"
"<div class=\"content\">"; "<div class=\"content\">";
@ -476,7 +482,7 @@ namespace http {
s << "<div class=\"listitem\">"; s << "<div class=\"listitem\">";
it->Print(s); it->Print(s);
if(it->LatencyIsKnown()) if(it->LatencyIsKnown())
s << " ( " << it->GetMeanLatency() << tr("ms") << " )"; s << " ( " << it->GetMeanLatency() << tr(/* Milliseconds */ "ms") << " )";
ShowTunnelDetails(s, it->GetState (), false, it->GetNumReceivedBytes ()); ShowTunnelDetails(s, it->GetState (), false, it->GetNumReceivedBytes ());
s << "</div>\r\n"; s << "</div>\r\n";
} }
@ -681,22 +687,22 @@ namespace http {
std::string webroot; i2p::config::GetOption("http.webroot", webroot); std::string webroot; i2p::config::GetOption("http.webroot", webroot);
/* commands */ /* commands */
s << "<b>" << tr("Router commands") << "</b><br>\r\n<br>\r\n<div class=\"commands\">\r\n"; s << "<b>" << tr("Router commands") << "</b><br>\r\n<br>\r\n<div class=\"commands\">\r\n";
s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_RUN_PEER_TEST << "&token=" << token << "\">" << tr("Run peer test") << "</a>\r\n"; s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_RUN_PEER_TEST << "&token=" << token << "\">" << tr("Run peer test") << "</a><br>\r\n";
//s << " <a href=\"/?cmd=" << HTTP_COMMAND_RELOAD_CONFIG << "\">Reload config</a><br>\r\n"; //s << " <a href=\"/?cmd=" << HTTP_COMMAND_RELOAD_CONFIG << "\">Reload config</a><br>\r\n";
if (i2p::context.AcceptsTunnels ()) if (i2p::context.AcceptsTunnels ())
s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_DISABLE_TRANSIT << "&token=" << token << "\">" << tr("Decline transit tunnels") << "</a>\r\n"; s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_DISABLE_TRANSIT << "&token=" << token << "\">" << tr("Decline transit tunnels") << "</a><br>\r\n";
else else
s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_ENABLE_TRANSIT << "&token=" << token << "\">" << tr("Accept transit tunnels") << "</a>\r\n"; s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_ENABLE_TRANSIT << "&token=" << token << "\">" << tr("Accept transit tunnels") << "</a><br>\r\n";
#if ((!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) || defined(ANDROID_BINARY)) #if ((!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) || defined(ANDROID_BINARY))
if (Daemon.gracefulShutdownInterval) if (Daemon.gracefulShutdownInterval)
s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_SHUTDOWN_CANCEL << "&token=" << token << "\">" << tr("Cancel graceful shutdown") << "</a>\r\n"; s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_SHUTDOWN_CANCEL << "&token=" << token << "\">" << tr("Cancel graceful shutdown") << "</a><br>\r\n";
else else
s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_SHUTDOWN_START << "&token=" << token << "\">" << tr("Start graceful shutdown") << "</a>\r\n"; s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_SHUTDOWN_START << "&token=" << token << "\">" << tr("Start graceful shutdown") << "</a><br>\r\n";
#elif defined(WIN32_APP) #elif defined(WIN32_APP)
if (i2p::util::DaemonWin32::Instance().isGraceful) if (i2p::util::DaemonWin32::Instance().isGraceful)
s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_SHUTDOWN_CANCEL << "&token=" << token << "\">" << tr("Cancel graceful shutdown") << "</a>\r\n"; s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_SHUTDOWN_CANCEL << "&token=" << token << "\">" << tr("Cancel graceful shutdown") << "</a><br>\r\n";
else else
s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_SHUTDOWN_START << "&token=" << token << "\">" << tr("Start graceful shutdown") << "</a>\r\n"; s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_SHUTDOWN_START << "&token=" << token << "\">" << tr("Start graceful shutdown") << "</a><br>\r\n";
#endif #endif
s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_SHUTDOWN_NOW << "&token=" << token << "\">" << tr("Force shutdown") << "</a>\r\n"; s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_SHUTDOWN_NOW << "&token=" << token << "\">" << tr("Force shutdown") << "</a>\r\n";
s << "</div>"; s << "</div>";
@ -718,6 +724,19 @@ namespace http {
s << " <input type=\"number\" min=\"0\" max=\"65535\" name=\"limit\" value=\"" << maxTunnels << "\">\r\n"; s << " <input type=\"number\" min=\"0\" max=\"65535\" name=\"limit\" value=\"" << maxTunnels << "\">\r\n";
s << " <button type=\"submit\">" << tr("Change") << "</button>\r\n"; s << " <button type=\"submit\">" << tr("Change") << "</button>\r\n";
s << "</form>\r\n<br>\r\n"; s << "</form>\r\n<br>\r\n";
std::string currLang = i2p::context.GetLanguage ()->GetLanguage(); // get current used language
s << "<b>" << tr("Change language") << "</b><br>\r\n";
s << "<form method=\"get\" action=\"" << webroot << "\">\r\n";
s << " <input type=\"hidden\" name=\"cmd\" value=\"" << HTTP_COMMAND_SETLANGUAGE << "\">\r\n";
s << " <input type=\"hidden\" name=\"token\" value=\"" << token << "\">\r\n";
s << " <select name=\"lang\" id=\"lang\">\r\n";
for (const auto& it: i2p::i18n::languages)
s << " <option value=\"" << it.first << "\"" << ((it.first.compare(currLang) == 0) ? " selected" : "") << ">" << it.second.LocaleName << "</option>\r\n";
s << " </select>\r\n";
s << " <button type=\"submit\">" << tr("Change") << "</button>\r\n";
s << "</form>\r\n<br>\r\n";
} }
void ShowTransitTunnels (std::stringstream& s) void ShowTransitTunnels (std::stringstream& s)
@ -1327,6 +1346,14 @@ namespace http {
s << "<a href=\"" << webroot << "?page=local_destination&b32=" << b32 << "\">" << tr("Return to destination page") << "</a>\r\n"; s << "<a href=\"" << webroot << "?page=local_destination&b32=" << b32 << "\">" << tr("Return to destination page") << "</a>\r\n";
return; return;
} }
else if (cmd == HTTP_COMMAND_SETLANGUAGE)
{
std::string lang = params["lang"];
std::string currLang = i2p::context.GetLanguage ()->GetLanguage();
if (currLang.compare(lang) != 0)
i2p::i18n::SetLanguage(lang);
}
else else
{ {
res.code = 400; res.code = 400;

View File

@ -18,8 +18,11 @@ namespace i2p
{ {
namespace i18n namespace i18n
{ {
namespace afrikaans // language namespace afrikaans // language namespace
{ {
// language name in lowercase
static std::string language = "afrikaans";
// See for language plural forms here: // See for language plural forms here:
// https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html // https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html
static int plural (int n) { static int plural (int n) {
@ -65,7 +68,7 @@ namespace afrikaans // language
std::shared_ptr<const i2p::i18n::Locale> GetLocale() std::shared_ptr<const i2p::i18n::Locale> GetLocale()
{ {
return std::make_shared<i2p::i18n::Locale>(strings, plurals, [] (int n)->int { return plural(n); }); return std::make_shared<i2p::i18n::Locale>(language, strings, plurals, [] (int n)->int { return plural(n); });
} }
} // language } // language

View File

@ -19,8 +19,11 @@ namespace i2p
{ {
namespace i18n namespace i18n
{ {
namespace english // language namespace english // language namespace
{ {
// language name in lowercase
static std::string language = "english";
// See for language plural forms here: // See for language plural forms here:
// https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html // https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html
static int plural (int n) { static int plural (int n) {
@ -39,7 +42,7 @@ namespace english // language
std::shared_ptr<const i2p::i18n::Locale> GetLocale() std::shared_ptr<const i2p::i18n::Locale> GetLocale()
{ {
return std::make_shared<i2p::i18n::Locale>(strings, plurals, [] (int n)->int { return plural(n); }); return std::make_shared<i2p::i18n::Locale>(language, strings, plurals, [] (int n)->int { return plural(n); });
} }
} // language } // language

View File

@ -17,16 +17,11 @@ namespace i18n
{ {
inline void SetLanguage(const std::string &lang) inline void SetLanguage(const std::string &lang)
{ {
if (!lang.compare("afrikaans")) const auto it = i2p::i18n::languages.find(lang);
i2p::context.SetLanguage (i2p::i18n::afrikaans::GetLocale()); if (it == i2p::i18n::languages.end()) // fallback
else if (!lang.compare("russian"))
i2p::context.SetLanguage (i2p::i18n::russian::GetLocale());
else if (!lang.compare("turkmen"))
i2p::context.SetLanguage (i2p::i18n::turkmen::GetLocale());
else if (!lang.compare("ukrainian"))
i2p::context.SetLanguage (i2p::i18n::ukrainian::GetLocale());
else // fallback
i2p::context.SetLanguage (i2p::i18n::english::GetLocale()); i2p::context.SetLanguage (i2p::i18n::english::GetLocale());
else
i2p::context.SetLanguage (it->second.LocaleFunc());
} }
inline std::string translate (const std::string& arg) inline std::string translate (const std::string& arg)

View File

@ -17,10 +17,17 @@ namespace i18n
{ {
public: public:
Locale ( Locale (
const std::string& language,
const std::map<std::string, std::string>& strings, const std::map<std::string, std::string>& strings,
const std::map<std::string, std::vector<std::string>>& plurals, const std::map<std::string, std::vector<std::string>>& plurals,
std::function<int(int)> formula std::function<int(int)> formula
): m_Strings (strings), m_Plurals (plurals), m_Formula (formula) { }; ): m_Language (language), m_Strings (strings), m_Plurals (plurals), m_Formula (formula) { };
// Get activated language name for webconsole
std::string GetLanguage() const
{
return m_Language;
}
std::string GetString (const std::string& arg) const std::string GetString (const std::string& arg) const
{ {
@ -50,11 +57,18 @@ namespace i18n
} }
private: private:
const std::string m_Language;
const std::map<std::string, std::string> m_Strings; const std::map<std::string, std::string> m_Strings;
const std::map<std::string, std::vector<std::string>> m_Plurals; const std::map<std::string, std::vector<std::string>> m_Plurals;
std::function<int(int)> m_Formula; std::function<int(int)> m_Formula;
}; };
struct langData
{
std::string LocaleName; //localized name
std::function<std::shared_ptr<const i2p::i18n::Locale> (void)> LocaleFunc;
};
// Add localization here with language name as namespace // Add localization here with language name as namespace
namespace afrikaans { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); } namespace afrikaans { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
namespace english { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); } namespace english { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
@ -62,6 +76,18 @@ namespace i18n
namespace turkmen { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); } namespace turkmen { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
namespace ukrainian { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); } namespace ukrainian { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
/**
* That map contains international language name lower-case and name in it's language
*/
static std::map<std::string, langData> languages
{
{ "afrikaans", {"Afrikaans", i2p::i18n::afrikaans::GetLocale} },
{ "english", {"English", i2p::i18n::english::GetLocale} },
{ "russian", {"русский язык", i2p::i18n::russian::GetLocale} },
{ "turkmen", {"türkmen dili", i2p::i18n::turkmen::GetLocale} },
{ "ukrainian", {"украї́нська мо́ва", i2p::i18n::ukrainian::GetLocale} },
};
} // i18n } // i18n
} // i2p } // i2p

View File

@ -18,8 +18,11 @@ namespace i2p
{ {
namespace i18n namespace i18n
{ {
namespace russian // language namespace russian // language namespace
{ {
// language name in lowercase
static std::string language = "russian";
// See for language plural forms here: // See for language plural forms here:
// https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html // https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html
static int plural (int n) { static int plural (int n) {
@ -28,23 +31,152 @@ namespace russian // language
static std::map<std::string, std::string> strings static std::map<std::string, std::string> strings
{ {
// HTTP Proxy {"Disabled", "Выключено"},
{"Enabled", "Включено"},
{"KiB", "КиБ"},
{"MiB", "МиБ"},
{"GiB", "ГиБ"},
{"building", "строится"},
{"failed", "неудачный"},
{"expiring", "истекает"},
{"established", "работает"},
{"unknown", "неизвестно"},
{"exploratory", "исследовательский"},
{"<b>i2pd</b> webconsole", "Веб-консоль <b>i2pd</b>"},
{"Main page", "Главная"},
{"Router commands", "Команды роутера"},
{"Local destinations", "Локальные назначения"},
{"LeaseSets", "Лизсеты"},
{"Tunnels", "Туннели"},
{"Transit tunnels", "Транзитные туннели"},
{"Transports", "Транспорты"},
{"I2P tunnels", "I2P туннели"},
{"SAM sessions", "SAM сессии"},
{"ERROR", "ОШИБКА"},
{"OK", "OK"},
{"Testing", "Тестирование"},
{"Firewalled", "Заблокировано извне"},
{"Unknown", "Неизвестно"},
{"Proxy", "Прокси"},
{"Mesh", "MESH-сеть"},
{"Error", "Ошибка"},
{"Clock skew", "Не точное время"},
{"Offline", "Оффлайн"},
{"Symmetric NAT", "Симметричный NAT"},
{"Uptime", "В сети"},
{"Network status", "Сетевой статус"},
{"Network status v6", "Сетевой статус v6"},
{"Stopping in", "Остановка через"},
{"Family", "Семейство"},
{"Tunnel creation success rate", "Успешно построенных туннелей"},
{"Received", "Получено"},
{"KiB/s", "КиБ/с"},
{"Sent", "Отправлено"},
{"Transit", "Транзит"},
{"Data path", "Путь к данным"},
{"Hidden content. Press on text to see.", "Скрытый контент. Нажмите на текст чтобы отобразить."},
{"Router Ident", "Идентификатор роутера"},
{"Router Family", "Семейство роутера"},
{"Router Caps", "Флаги роутера"},
{"Version", "Версия"},
{"Our external address", "Наш внешний адрес"},
{"supported", "поддерживается"},
{"Routers", "Роутеры"},
{"Floodfills", "Флудфилы"},
{"Client Tunnels", "Клиентские туннели"},
{"Transit Tunnels", "Транзитные туннели"},
{"Services", "Сервисы"},
{"Local Destinations", "Локальные назначения"},
{"Encrypted B33 address", "Шифрованные B33 адреса"},
{"Address registration line", "Строка регистрации адреса"},
{"Domain", "Домен"},
{"Generate", "Сгенерировать"},
{"<b>Note:</b> result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "<b>Примечание:</b> полученная строка может быть использована только для регистрации доменов второго уровня (example.i2p). Для регистрации поддоменов используйте i2pd-tools."},
{"Address", "Адрес"},
{"Type", "Тип"},
{"EncType", "ТипШифр"},
{"Inbound tunnels", "Входящие туннели"},
{"ms", "мс"},
{"Outbound tunnels", "Исходящие туннели"},
{"Tags", "Теги"},
{"Incoming", "Входящие"},
{"Outgoing", "Исходящие"},
{"Destination", "Назначение"},
{"Amount", "Количество"},
{"Incoming Tags", "Входящие Теги"},
{"Tags sessions", "Сессии Тегов"},
{"Status", "Статус"},
{"Local Destination", "Локальное назначение"},
{"Streams", "Стримы"},
{"Close stream", "Закрыть стрим"},
{"I2CP session not found", "I2CP сессия не найдена"},
{"I2CP is not enabled", "I2CP не включен"},
{"Invalid", "Некорректный"},
{"Store type", "Тип хранилища"},
{"Expires", "Истекает"},
{"Non Expired Leases", "Не истекшие Lease-ы"},
{"Gateway", "Шлюз"},
{"TunnelID", "ID туннеля"},
{"EndDate", "Заканчивается"},
{"not floodfill", "не флудфил"},
{"Queue size", "Размер очереди"},
{"Run peer test", "Запустить тестирование"},
{"Decline transit tunnels", "Отклонять транзитные туннели"},
{"Accept transit tunnels", "Принимать транзитные туннели"},
{"Cancel graceful shutdown", "Отменить плавную остановку"},
{"Start graceful shutdown", "Запустить плавную остановку"},
{"Force shutdown", "Принудительная остановка"},
{"<b>Note:</b> any action done here are not persistent and not changes your config files.", "<b>Примечание:</b> любое действие произведенное здесь не является постоянным и не изменяет ваши конфигурационные файлы."},
{"Logging level", "Уровень логирования"},
{"Transit tunnels limit", "Лимит транзитных туннелей"},
{"Change", "Изменить"},
{"Change language", "Изменение языка"},
{"no transit tunnels currently built", "нет построенных транзитных туннелей"},
{"SAM disabled", "SAM выключен"},
{"no sessions currently running", "нет запущенных сессий"},
{"SAM session not found", "SAM сессия не найдена"},
{"SAM Session", "SAM сессия"},
{"Server Tunnels", "Серверные туннели"},
{"Client Forwards", "Клиентские перенаправления"},
{"Server Forwards", "Серверные перенаправления"},
{"Unknown page", "Неизвестная страница"},
{"Invalid token", "Неверный токен"},
{"SUCCESS", "УСПЕШНО"},
{"Stream closed", "Стрим закрыт"},
{"Stream not found or already was closed", "Стрим не найден или уже закрыт"},
{"Destination not found", "Точка назначения не найдена"},
{"StreamID can't be null", "StreamID не может быть пустым"},
{"Return to destination page", "Вернуться на страницу точки назначения"},
{"You will be redirected back in 5 seconds", "Вы будете переадресованы назад через 5 секунд"},
{"Transit tunnels count must not exceed 65535", "Число транзитных туннелей не должно превышать 65535"},
{"Back to commands list", "Вернуться к списку команд"},
{"Register at reg.i2p", "Зарегистрировать на reg.i2p"},
{"Description", "Описание"},
{"A bit information about service on domain", "Немного информации о сервисе на домене"},
{"Submit", "Отправить"},
{"Domain can't end with .b32.i2p", "Домен не может заканчиваться на .b32.i2p"},
{"Domain must end with .i2p", "Домен должен заканчиваться на .i2p"},
{"Such destination is not found", "Такая точка назначения не найдена"},
{"Unknown command", "Неизвестная команда"},
{"Command accepted", "Команда принята"},
{"You will be redirected in 5 seconds", "Вы будете переадресованы через 5 секунд"},
{"Proxy error", "Ошибка прокси"}, {"Proxy error", "Ошибка прокси"},
{"Proxy info", "Информация прокси"}, {"Proxy info", "Информация прокси"},
{"Proxy error: Host not found", "Ошибка прокси: Адрес не найден"}, {"Proxy error: Host not found", "Ошибка прокси: Узел не найден"},
{"Remote host not found in router's addressbook", "Запрошенный адрес не найден в адресной книге роутера"}, {"Remote host not found in router's addressbook", "Запрошенный узел не найден в адресной книге роутера"},
{"You may try to find this host on jump services below", "Вы можете попробовать найти адрес на джамп сервисах ниже"}, {"You may try to find this host on jump services below", "Вы можете попробовать найти узел через джамп сервисы ниже"},
{"Invalid request", "Некорректный запрос"}, {"Invalid request", "Некорректный запрос"},
{"Proxy unable to parse your request", "Прокси не может разобрать ваш запрос"}, {"Proxy unable to parse your request", "Прокси не может разобрать ваш запрос"},
{"addresshelper is not supported", "addresshelper не поддерживается"}, {"addresshelper is not supported", "addresshelper не поддерживается"},
{"Host", "Адрес"}, {"Host", "Узел"},
{"added to router's addressbook from helper", "добавлен в адресную книгу роутера через хелпер"}, {"added to router's addressbook from helper", "добавлен в адресную книгу роутера через хелпер"},
{"already in router's addressbook", "уже в адресной книге роутера"},
{"Click", "Нажмите"}, {"Click", "Нажмите"},
{"here", "здесь"}, {"here", "здесь"},
{"to proceed", "чтобы продолжить"}, {"to proceed", "чтобы продолжить"},
{"to update record", "чтобы обновить запись"},
{"Addresshelper found", "Найден addresshelper"}, {"Addresshelper found", "Найден addresshelper"},
{"already in router's addressbook", "уже в адресной книге роутера"},
{"to update record", "чтобы обновить запись"},
{"Invalid Request", "неверный запрос"},
{"invalid request uri", "некорректный URI запроса"}, {"invalid request uri", "некорректный URI запроса"},
{"Can't detect destination host from request", "Не удалось определить адрес назначения из запроса"}, {"Can't detect destination host from request", "Не удалось определить адрес назначения из запроса"},
{"Outproxy failure", "Ошибка внешнего прокси"}, {"Outproxy failure", "Ошибка внешнего прокси"},
@ -63,169 +195,13 @@ namespace russian // language
{"cannot connect", "не удалось подключиться"}, {"cannot connect", "не удалось подключиться"},
{"http out proxy not implemented", "поддержка внешнего HTTP прокси сервера не реализована"}, {"http out proxy not implemented", "поддержка внешнего HTTP прокси сервера не реализована"},
{"cannot connect to upstream http proxy", "не удалось подключиться к вышестоящему HTTP прокси серверу"}, {"cannot connect to upstream http proxy", "не удалось подключиться к вышестоящему HTTP прокси серверу"},
{"Host is down", "Адрес недоступен"}, {"Host is down", "Узел недоступен"},
{"Can't create connection to requested host, it may be down. Please try again later.", {"Can't create connection to requested host, it may be down. Please try again later.", "Не удалось установить соединение к запрошенному узлу, возможно он не в сети. Попробуйте повторить запрос позже."},
"Не удалось установить соединение к запрошенному адресу, возможно он не в сети. Попробуйте повторить запрос позже."},
// Webconsole //
// cssStyles
{"Disabled", "Выключено"},
{"Enabled", "Включено"},
// ShowTraffic
{"KiB", "КиБ"},
{"MiB", "МиБ"},
{"GiB", "ГиБ"},
// ShowTunnelDetails
{"building", "строится"},
{"failed", "неудачный"},
{"expiring", "истекает"},
{"established", "работает"},
{"exploratory", "исследовательский"},
{"unknown", "неизвестно"},
{"<b>i2pd</b> webconsole", "Веб-консоль <b>i2pd</b>"},
// ShowPageHead
{"Main page", "Главная"},
{"Router commands", "Команды роутера"},
{"Local destinations", "Локальные назнач."},
{"LeaseSets", "Лизсеты"},
{"Tunnels", "Туннели"},
{"Transit tunnels", "Транзит. туннели"},
{"Transports", "Транспорты"},
{"I2P tunnels", "I2P туннели"},
{"SAM sessions", "SAM сессии"},
// Network Status
{"OK", "OK"},
{"Testing", "Тестирование"},
{"Firewalled", "Заблокировано извне"},
{"Unknown", "Неизвестно"},
{"Proxy", "Прокси"},
{"Mesh", "MESH-сеть"},
{"Error", "Ошибка"},
{"Clock skew", "Не точное время"},
{"Offline", "Оффлайн"},
{"Symmetric NAT", "Симметричный NAT"},
// Status
{"Uptime", "В сети"},
{"Network status", "Сетевой статус"},
{"Network status v6", "Сетевой статус v6"},
{"Stopping in", "Остановка через"},
{"Family", "Семейство"},
{"Tunnel creation success rate", "Успешно построенных туннелей"},
{"Received", "Получено"},
{"Sent", "Отправлено"},
{"Transit", "Транзит"},
{"KiB/s", "КиБ/с"},
{"Data path", "Путь к данным"},
{"Hidden content. Press on text to see.", "Скрытый контент. Нажмите на текст чтобы отобразить."},
{"Router Ident", "Идентификатор роутера"},
{"Router Family", "Семейство роутера"},
{"Router Caps", "Флаги роутера"},
{"Version", "Версия"},
{"Our external address", "Наш внешний адрес"},
{"supported", "поддерживается"},
{"Routers", "Роутеры"},
{"Floodfills", "Флудфилы"},
{"LeaseSets", "Лизсеты"},
{"Client Tunnels", "Клиентские туннели"},
{"Transit Tunnels", "Транзитные туннели"},
{"Services", "Сервисы"},
// ShowLocalDestinations
{"Local Destinations", "Локальные назначения"},
// ShowLeaseSetDestination
{"Encrypted B33 address", "Шифрованные B33 адреса"},
{"Address registration line", "Строка регистрации адреса"},
{"Domain", "Домен"},
{"Generate", "Сгенерировать"},
{"<b>Note:</b> result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.",
"<b>Примечание:</b> полученная строка может быть использована только для регистрации доменов второго уровня. Для регистрации поддоменов используйте i2pd-tools."},
{"Address", "Адрес"},
{"Type", "Тип"},
{"EncType", "ТипШифр"},
{"Inbound tunnels", "Входящие туннели"},
{"Outbound tunnels", "Исходящие туннели"},
{"ms", "мс"}, // milliseconds
{"Tags", "Теги"},
{"Incoming", "Входящие"},
{"Outgoing", "Исходящие"},
{"Destination", "Назначение"},
{"Amount", "Количество"},
{"Incoming Tags", "Входящие Теги"},
{"Tags sessions", "Сессии Тегов"},
{"Status", "Статус"},
// ShowLocalDestination
{"Local Destination", "Локальное назначение"},
{"Streams", "Стримы"},
{"Close stream", "Закрыть стрим"},
// ShowI2CPLocalDestination
{"I2CP session not found", "I2CP сессия не найдена"},
{"I2CP is not enabled", "I2CP не включен"},
// ShowLeasesSets
{"Invalid", "Некорректный"},
{"Store type", "Тип хранилища"},
{"Expires", "Истекает"},
{"Non Expired Leases", "Не истекшие Lease-ы"},
{"Gateway", "Шлюз"},
{"TunnelID", "ID туннеля"},
{"EndDate", "Заканчивается"},
{"not floodfill", "не флудфил"},
// ShowTunnels
{"Queue size", "Размер очереди"},
// ShowCommands
{"Run peer test", "Запустить тестирование"},
{"Decline transit tunnels", "Отклонять транзитные туннели"},
{"Accept transit tunnels", "Принимать транзитные туннели"},
{"Cancel graceful shutdown", "Отменить плавную остановку"},
{"Start graceful shutdown", "Запустить плавную остановку"},
{"Force shutdown", "Принудительная остановка"},
{"<b>Note:</b> any action done here are not persistent and not changes your config files.",
"<b>Примечание:</b> любое действие произведенное здесь не является постоянным и не изменяет ваши конфигурационные файлы."},
{"Logging level", "Уровень логирования"},
{"Transit tunnels limit", "Лимит транзитных туннелей"},
{"Change", "Изменить"},
// ShowTransitTunnels
{"no transit tunnels currently built", "нет построенных транзитных туннелей"},
// ShowSAMSessions/ShowSAMSession
{"SAM disabled", "SAM выключен"},
{"SAM session not found", "SAM сессия не найдена"},
{"no sessions currently running", "нет запущенных сессий"},
{"SAM Session", "SAM сессия"},
// ShowI2PTunnels
{"Server Tunnels", "Серверные туннели"},
{"Client Forwards", "Клиентские перенаправления"},
{"Server Forwards", "Серверные перенаправления"},
// HandlePage
{"Unknown page", "Неизвестная страница"},
// HandleCommand, ShowError
{"Invalid token", "Неверный токен"},
{"SUCCESS", "УСПЕШНО"},
{"ERROR", "ОШИБКА"},
{"Unknown command", "Неизвестная команда"},
{"Command accepted", "Команда принята"},
{"Back to commands list", "Вернуться к списку команд"},
{"You will be redirected in 5 seconds", "Вы будете переадресованы через 5 секунд"},
// HTTP_COMMAND_KILLSTREAM
{"Stream closed", "Стрим закрыт"},
{"Stream not found or already was closed", "Стрим не найден или уже закрыт"},
{"Destination not found", "Точка назначения не найдена"},
{"StreamID can't be null", "StreamID не может быть пустым"},
{"Return to destination page", "Вернуться на страницу точки назначения"},
{"You will be redirected back in 5 seconds", "Вы будете переадресованы назад через 5 секунд"},
// HTTP_COMMAND_LIMITTRANSIT
{"Transit tunnels count must not exceed 65535", "Число транзитных туннелей не должно превышать 65535"},
// HTTP_COMMAND_GET_REG_STRING
{"Register at reg.i2p", "Зарегистрировать на reg.i2p"},
{"Description", "Описание"},
{"A bit information about service on domain", "Немного информации о сервисе на домене"},
{"Submit", "Отправить"},
{"Domain can't end with .b32.i2p", "Домен не может заканчиваться на .b32.i2p"},
{"Domain must end with .i2p", "Домен должен заканчиваться на .i2p"},
{"Such destination is not found", "Такая точка назначения не найдена"},
{"", ""}, {"", ""},
}; };
static std::map<std::string, std::vector<std::string>> plurals static std::map<std::string, std::vector<std::string>> plurals
{ {
// ShowUptime
{"days", {"день", "дня", "дней"}}, {"days", {"день", "дня", "дней"}},
{"hours", {"час", "часа", "часов"}}, {"hours", {"час", "часа", "часов"}},
{"minutes", {"минуту", "минуты", "минут"}}, {"minutes", {"минуту", "минуты", "минут"}},
@ -235,7 +211,7 @@ namespace russian // language
std::shared_ptr<const i2p::i18n::Locale> GetLocale() std::shared_ptr<const i2p::i18n::Locale> GetLocale()
{ {
return std::make_shared<i2p::i18n::Locale>(strings, plurals, [] (int n)->int { return plural(n); }); return std::make_shared<i2p::i18n::Locale>(language, strings, plurals, [] (int n)->int { return plural(n); });
} }
} // language } // language

View File

@ -18,8 +18,11 @@ namespace i2p
{ {
namespace i18n namespace i18n
{ {
namespace turkmen // language namespace turkmen // language namespace
{ {
// language name in lowercase
static std::string language = "turkmen";
// See for language plural forms here: // See for language plural forms here:
// https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html // https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html
static int plural (int n) { static int plural (int n) {
@ -234,7 +237,7 @@ namespace turkmen // language
std::shared_ptr<const i2p::i18n::Locale> GetLocale() std::shared_ptr<const i2p::i18n::Locale> GetLocale()
{ {
return std::make_shared<i2p::i18n::Locale>(strings, plurals, [] (int n)->int { return plural(n); }); return std::make_shared<i2p::i18n::Locale>(language, strings, plurals, [] (int n)->int { return plural(n); });
} }
} // language } // language

View File

@ -18,8 +18,11 @@ namespace i2p
{ {
namespace i18n namespace i18n
{ {
namespace ukrainian // language namespace ukrainian // language namespace
{ {
// language name in lowercase
static std::string language = "ukrainian";
// See for language plural forms here: // See for language plural forms here:
// https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html // https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html
static int plural (int n) { static int plural (int n) {
@ -207,7 +210,7 @@ namespace ukrainian // language
std::shared_ptr<const i2p::i18n::Locale> GetLocale() std::shared_ptr<const i2p::i18n::Locale> GetLocale()
{ {
return std::make_shared<i2p::i18n::Locale>(strings, plurals, [] (int n)->int { return plural(n); }); return std::make_shared<i2p::i18n::Locale>(language, strings, plurals, [] (int n)->int { return plural(n); });
} }
} // language } // language