Compare commits

...

16 Commits
master ... i18n

Author SHA1 Message Date
jacob1
d90a718818 Some uncomitted warning fixes I had 2020-04-06 23:38:36 -04:00
mniip
6aeb0aa74b remove _ascii and undeprecate conversions from string literals 2020-03-31 06:30:56 +03:00
mniip
e317164c2b Fixes for msvc warnings 2020-03-25 00:07:10 +03:00
mniip
8e67a6ff89 i18n for everything else 2020-03-24 22:56:27 +03:00
mniip
7f4aae7e99 Refactor even more stuff 2020-03-24 21:50:04 +03:00
mniip
56f2872104 Add plurals for saves/stamps 2020-03-24 19:17:34 +03:00
mniip
bb4f242e0b Add support for plural forms 2020-03-24 19:17:34 +03:00
mniip
a16a4936a5 Refactor more stuff 2020-03-24 19:17:18 +03:00
mniip
18cd57006b Remove swear words from the source 2020-03-24 19:17:16 +03:00
mniip
cae041cdee Refactor introtext and rules into the locale 2020-03-24 13:01:53 +03:00
mniip
53c5487abe Refactor stuff for i18n 2020-03-24 12:00:47 +03:00
mniip
5b20bc534f i18n headers 2020-03-20 08:40:01 +03:00
mniip
51f77f08b7 Internationalize simulation data (element names, descriptions, tools, walls, menus) 2020-03-20 07:32:07 +03:00
mniip
131accb5ac Add i18n debug stuff 2020-03-20 07:02:16 +03:00
mniip
bf05a14ef5 Temporarily deprecate character literal to string conversions. 2020-03-20 05:45:13 +03:00
mniip
4726f55c3e Initial i18n/l10n support 2020-03-11 07:14:40 +03:00
271 changed files with 1657 additions and 1184 deletions

View File

@ -70,6 +70,7 @@ AddSconsOption('opengl', False, False, "Build with OpenGL interface support.")
AddSconsOption('opengl-renderer', False, False, "Build with OpenGL renderer support (turns on --opengl).") #Note: this has nothing to do with --renderer, only tells the game to render particles with opengl
AddSconsOption('renderer', False, False, "Build the save renderer.")
AddSconsOption('font', False, False, "Build the font editor.")
AddSconsOption('i18n-debug', False, False, "Instrument the binary for debugging internationalization")
AddSconsOption('wall', False, False, "Error on all warnings.")
AddSconsOption('no-warnings', False, False, "Disable all compiler warnings.")
@ -404,7 +405,8 @@ elif not GetOption('help'):
env = conf.Finish()
if not msvc:
env.Append(CXXFLAGS=['-std=c++11', '-U__STRICT_ANSI__'])
env.Append(CXXFLAGS=['-std=c++11' if not GetOption('i18n-debug') else '-std=c++14'])
env.Append(CXXFLAGS=['-U__STRICT_ANSI__'])
env.Append(CXXFLAGS=['-Wno-invalid-offsetof'])
if platform == "Linux":
env.Append(CXXFLAGS=['-Wno-unused-result'])
@ -519,6 +521,9 @@ if GetOption('renderer'):
if GetOption('font'):
env.Append(CPPDEFINES=['FONTEDITOR'])
if GetOption('i18n-debug'):
env.Append(CPPDEFINES=['I18N_DEBUG'])
if GetOption("wall"):
if msvc:
env.Append(CCFLAGS=['/WX'])
@ -555,7 +560,7 @@ if GetOption('ignore-updates'):
#Generate list of sources to compile
sources = Glob("src/*.cpp") + Glob("src/*/*.cpp") + Glob("src/*/*/*.cpp") + Glob("data/*.cpp")
sources = Glob("src/*.cpp") + Glob("src/*/*.cpp") + Glob("src/*/*/*.cpp") + Glob("data/*.cpp") + Glob("data/localization/*.cpp")
if not GetOption('nolua') and not GetOption('renderer') and not GetOption('font'):
sources += Glob("src/lua/socket/*.c") + Glob("src/lua/LuaCompat.c")

View File

@ -1,59 +0,0 @@
#pragma once
const char *const introTextData =
"\blThe Powder Toy - Version " MTOS(SAVE_VERSION) "." MTOS(MINOR_VERSION) " - https://powdertoy.co.uk, irc.freenode.net #powder\n"
"\xEE\x81\xA9\xEE\x81\xA9\xEE\x81\xA9\xEE\x81\xA9\xEE\x81\xA9\xEE\x81\xA9\xEE\x81\xA9\xEE\x81\xA9\xEE\x81\xA9\xEE\x81\xA9\xEE\x81\xA9\xEE\x81\xA9\xEE\x81\xA9\xEE\x81\xA9\xEE\x81\xA9\xEE\x81\xA9\xEE\x81\xA9\xEE\x81\xA9\xEE\x81\xA9\n"
"\n"
"\bgControl+C/V/X are Copy, Paste and cut respectively.\n"
"\bgTo choose a material, hover over one of the icons on the right, it will show a selection of elements in that group.\n"
"\bgPick your material from the menu using mouse left/right buttons.\n"
"Draw freeform lines by dragging your mouse left/right button across the drawing area.\n"
"Shift+drag will create straight lines of particles.\n"
"Ctrl+drag will result in filled rectangles.\n"
"Ctrl+Shift+click will flood-fill a closed area.\n"
"Use the mouse scroll wheel, or '[' and ']', to change the tool size for particles.\n"
"Middle click or Alt+Click to \"sample\" the particles.\n"
"Ctrl+Z will act as Undo.\n"
"\n\boUse 'Z' for a zoom tool. Click to make the drawable zoom window stay around. Use the wheel to change the zoom strength.\n"
"The spacebar can be used to pause physics. Use 'F' to step ahead by one frame.\n"
"Use 'S' to save parts of the window as 'stamps'. 'L' loads the most recent stamp, 'K' shows a library of stamps you saved.\n"
"Use 'P' to take a screenshot and save it into the current directory.\n"
"Use 'H' to toggle the HUD. Use 'D' to toggle debug mode in the HUD.\n"
"\n"
"Contributors: \bgStanislaw K Skowronek (Designed the original Powder Toy),\n"
"\bgSimon Robertshaw, Skresanov Savely, cracker64, Catelite, Bryan Hoyle, Nathan Cousins, jacksonmj,\n"
"\bgFelix Wallin, Lieuwe Mosch, Anthony Boot, Matthew \"me4502\", MaksProg, jacob1, mniip, LBPHacker\n"
"\n"
#ifndef BETA
"\bgTo use online features such as saving, you need to register at: \brhttps://powdertoy.co.uk/Register.html\n"
#else
"\brThis is a BETA, you cannot save things publicly. If you are planning on publishing any saves, use the release version\n"
#endif
"\n"
"\bt" MTOS(SAVE_VERSION) "." MTOS(MINOR_VERSION) "." MTOS(BUILD_NUM) " " IDENT_PLATFORM " "
#ifdef SNAPSHOT
"SNAPSHOT " MTOS(SNAPSHOT_ID) " "
#elif MOD_ID > 0
"MODVER " MTOS(SNAPSHOT_ID) " "
#endif
#ifdef X86
"X86 "
#endif
#ifdef X86_SSE
"X86_SSE "
#endif
#ifdef X86_SSE2
"X86_SSE2 "
#endif
#ifdef X86_SSE3
"X86_SSE3 "
#endif
#ifdef LUACONSOLE
"LUACONSOLE "
#endif
#ifdef GRAVFFT
"GRAVFFT "
#endif
#ifdef REALISTIC
"REALISTIC"
#endif
;

147
data/localization/EN.cpp Normal file
View File

@ -0,0 +1,147 @@
#include "Config.h"
#include "common/Localization.h"
#include "common/Internationalization.h"
struct LocaleEN : public Locale
{
String GetName() const override { return "English"; }
size_t GetPluralIndex(size_t n) const override
{
// 0: singular, 1: plural
return n == 1 ? 0 : 1;
}
void Set() const override
{
using i18n::translation;
using i18n::pluralForm;
pluralForm("save") = {"save", "saves"};
pluralForm("stamp") = {"stamp", "stamps"};
}
String GetIntroText() const override
{
return
U"\blThe Powder Toy - Version " MTOS(SAVE_VERSION) "." MTOS(MINOR_VERSION) " - https://powdertoy.co.uk, irc.freenode.net #powder\n"
U"\uE069\uE069\uE069\uE069\uE069\uE069\uE069\uE069\uE069\uE069\uE069\uE069\uE069\uE069\uE069\uE069\uE069\uE069\uE069\n"
"\n"
"\bgControl+C/V/X are Copy, Paste and cut respectively.\n"
"\bgTo choose a material, hover over one of the icons on the right, it will show a selection of elements in that group.\n"
"\bgPick your material from the menu using mouse left/right buttons.\n"
"Draw freeform lines by dragging your mouse left/right button across the drawing area.\n"
"Shift+drag will create straight lines of particles.\n"
"Ctrl+drag will result in filled rectangles.\n"
"Ctrl+Shift+click will flood-fill a closed area.\n"
"Use the mouse scroll wheel, or '[' and ']', to change the tool size for particles.\n"
"Middle click or Alt+Click to \"sample\" the particles.\n"
"Ctrl+Z will act as Undo.\n"
"\n\boUse 'Z' for a zoom tool. Click to make the drawable zoom window stay around. Use the wheel to change the zoom strength.\n"
"The spacebar can be used to pause physics. Use 'F' to step ahead by one frame.\n"
"Use 'S' to save parts of the window as 'stamps'. 'L' loads the most recent stamp, 'K' shows a library of stamps you saved.\n"
"Use 'P' to take a screenshot and save it into the current directory.\n"
"Use 'H' to toggle the HUD. Use 'D' to toggle debug mode in the HUD.\n"
"\n"
"Contributors: \bgStanislaw K Skowronek (Designed the original Powder Toy),\n"
"\bgSimon Robertshaw, Skresanov Savely, cracker64, Catelite, Bryan Hoyle, Nathan Cousins, jacksonmj,\n"
"\bgFelix Wallin, Lieuwe Mosch, Anthony Boot, Matthew \"me4502\", MaksProg, jacob1, mniip, LBPHacker\n"
"\n"
#ifndef BETA
"\bgTo use online features such as saving, you need to register at: \brhttps://powdertoy.co.uk/Register.html\n"
#else
"\brThis is a BETA, you cannot save things publicly. If you are planning on publishing any saves, use the release version\n"
#endif
;
}
String GetSavePublishingInfo() const override
{
return
U"In The Powder Toy, one can save simulations to their account in two privacy levels: Published and unpublished. You can choose which one by checking or unchecking the 'publish' checkbox. Saves are unpublished by default, so if you do not check publish nobody will be able to see your saves.\n"
"\n"
"\btPublished saves\bw will appear on the 'By Date' feed and will be seen by many people. These saves also contribute to your Average Score, which is displayed publicly on your profile page on the website. Publish saves that you want people to see so they can comment and vote on.\n"
"\btUnpublished saves\bw will not be shown on the 'By Date' feed. These will not contribute to your Average Score. They are not completely private though, as anyone who knows the save id will be able to view it. You can give the save id out to show specific people the save but not allow just everyone to see it.\n"
"\n"
"To quickly resave a save, open it and click the left side of the split resave button to \bt'Reupload the current simulation'\bw. If you want to change the description or change the published status, you can click the right side to \bt'Modify simulation properties'\bw. Note that you can't change the name of saves; this will create an entirely new save with no comments, votes, or tags; separate from the original.\n"
"You may want to publish an unpublished save after it is finished, or to unpublish some currently published ones. You can do this by opening the save, selecting the 'Modify simulation properties' button, and changing the published status there. You can also \btunpublish or delete saves\bw by selecting them in the 'my own' section of the browser and clicking either one of the buttons that appear on bottom.\n"
"If a save is under a week old and gains popularity fast, it will be automatically placed on the \btfront page\bw. Only published saves will be able to get here. Moderators can also choose to promote any save onto the front page, but this happens rarely. They can also demote any save from the front page that breaks a rule or they feel doesn't belong.\n"
"Once you make a save, you can resave it as many times as you want. A short previous \btsave history\bw is saved, just right click any save in the save browser and select 'View History' to view it. This is useful for when you accidentally save something you didn't mean to and want to go back to the old version.\n";
}
String GetRules() const override
{
return
U"\boSection S: Social and Community Rules\n"
"\bwThere are a few rules you should follow while interacting with the community. These rules are enforced by staff members and any issues related to violations of these rules may be brought to our attention by users. This section applies to saves uploaded, comments area, forums, and other areas of the community.\n"
"\n"
"\bt1. Try to use proper grammar.\bw English is the official community language, but use is not required in regional or cultural groups. If you cannot write English well, we advise that you use Google Translate.\n"
"\bt2. Do not spam.\bw There's not a one size fits all definition here, but the idea is usually obvious. In addition, the following are seen as spam and may be hidden or deleted:\n"
"- Posting multiple threads on the same subject. Try to combine threads on game feedback or suggestions into one thread.\n"
"- Bumping an old thread by replying. This is what we call 'necro' or 'necroing'. The content of the thread may be stale (fixing issues, ideas, etc). We recommend posting a new thread for an updated or more current response.\n"
"- Posting on a thread with '+1' or other short replies. There's no need to constantly bump a thread and make finding replies difficult. Replies are great for constructive feedback, while the '+1' button is to show your support for the content.\n"
"- Comments that are excessively long or gibberish. Making comments such as repeating the same letter or have little to no intended purpose, fall under this rule. Comments that are in a different language are exempt.\n"
"- Excessive formatting. UPPERCASE, Bold, and italics can be nice with moderate use, but please do not use them throughout the entire post.\n"
"\bt3. Keep swearing to a minimum.\bw Comments or saves containing swearing are at risk of being deleted. This also includes swearing in other languages.\n"
"\bt4. Refrain from uploading sexually explicit, offensive, or other inappropriate materials.\bw\n"
"- These include, but are not limited to: sex, drugs, racism, excessive politics, or anything that offends or insults a group of people.\n"
"- Reference to these topics in other languages is also prohibited. Do not attempt to bypass this rule.\n"
"- Posting URLs or images that violate this rule is prohibited. This includes links or text in your profile information.\n"
"\bt5. Do not advertise third-party games, sites, or other places not related to The Powder Toy.\bw\n"
"- Mainly this rule is intended to prevent people going through and advertising their own games and products.\n"
"- Unauthorized or unofficial community gathering places, such as Discord, are prohibited.\n"
"\bt6. Trolling is not allowed.\bw As with some rules, there's no clear definition. Users who repeatedly troll are far more likely to be banned and recieve longer bans than others.\n"
"\bt7. Do not impersonate anyone.\bw Registering accounts with names intentionally similar to other users in our community or other online communities is prohibited.\n"
"\bt8. Do not post about moderator decisions or issues.\bw If there is a problem regarding a ban on your account or content removal, please contact a moderator through the messages system. Otherwise, discussion about moderator actions should be avoided.\n"
"\bt9. Avoid backseat moderating.\bw Moderators are the ones who make the decisions. Users should refrain from threatening bans or possible results from breaking a rule. If there is a possible issue or you are unsure, we recommend reporting the issue through the 'Report' button or via the messaging system on the website.\n"
"\bt10. Condoning of breaking common laws is prohibited.\bw The jurisdiction of which country's laws applies is not clear, but there are some common ones to know. These include, but not limited to:\n"
"- Piracy of software, music, bagels, etc.\n"
"- Hacking / Stealing accounts\n"
"- Theft / Fraud\n"
"\bt11. Do not stalk or harass any user.\bw This has been a growing problem in recent years by different methods, but generally these include:\n"
"- 'Doxing' user(s) to find where they live or their real identity\n"
"- Constantly messaging a user when they wish to refrain from any contact\n"
"- Mass downvoting saves\n"
"- Posting rude or unnecessary comments on someone's content (saves, forum threads, etc)\n"
"- Coercing a group of users to 'target' a user\n"
"- Personal arguments or hatred. This could be arguing in the comments or making hate saves\n"
"- Discrimination, in general, of people. This could be religious, ethnic, etc.\n"
"\n"
"\boSection G: In-Game Rules\n"
"\bwThis section of the rules is focused on in-game actions. Though, Section S also applies in-game, the following rules are more specialized to in-game community interaction.\n"
"\bt1. Don't claim other people's work.\bw This could be simply re-uploading another user's or utilizing large sections of saves. Derivative works are allowed, with proper usage. Should you utilize someone's work, by default you must credit the author. Unless the author has explicitly noted different usage terms, this is the standard policy. Derivative works are characterized by innovative usage and originality percentage (ie. how much is original versus someone's work?). Stolen saves will be unpublished or disabled.\n"
"\bt2. Self-voting or vote fraud is not allowed.\bw This is defined as making multiple accounts to vote on your own saves or the saves of others. We enforce this rule strictly, therefore, you must understand that there are very few successful ban appeals. Please ensure you and other accounts are not voting from the same household. All alternate accounts will be permanently banned, the main account will be temporarily banned and any affected saves will be disabaled.\n"
"\bt3. Asking for votes of any kind is frowned upon.\bw Saves which do this will be unpublished until the issue is fixed. Examples of such that are under this rules are:\n"
"- Signs that may hint at voting up or down. The signature green arrow or asking for votes goes under this rule.\n"
"- Gimmicks that ask for votes. These might be a total number of votes in exchange for something, like '100 votes and I'll make a better version'. This is what we define as vote farming. Any type of vote farming is not allowed.\n"
"- Asking for votes in return for usage of a save or for any other reason is prohibited.\n"
"\bt4. Do not spam.\bw As mentioned earlier, there are no standards for what counts as spam. Here are some examples that may qualify as spamming:\n"
"- Uploading or re-uploading similar saves within a short amount of time. Don't try to circumvent the system to have your saves seen/voted by people. This includes uploading 'junk' or 'blank' saves with little to no purpose. These saves will be unpublished.\n"
"- Uploading text-only saves. These may be announcements or looking for help of sorts. We have the forums and comments area available for many purposes these text-only saves would serve. These saves will be removed from front page.\n"
"- Uploading art saves is not strictly prohibited, but may result in a front-page demotion. We like to see usage of the variety of elements in a creative manner. Lack of these factors (such as in deco-only saves) will typically result in a front-page demotion\n"
"\bt5. Refrain from uploading sexually explicit or other inappropriate materials. These saves will be deleted and will lead to a ban.\bw\n"
"- These include, but are not limited to: sex, drugs, racism, excessive politics, or anything that offends or insults a group of people.\n"
"- Don't try to circumvent this rule. Anything that intentionally refers to these concepts/ideas by direct or indirect means falls under this rule.\n"
"- Reference to these topics in other languages is also prohibited. Do not attempt to bypass this rule.\n"
"- Posting URLs or images that violate this rule is prohibited. This includes links or text in your profile information.\n"
"\bt6. Image plotting is strictly prohibited.\bw This includes usage of scripting or any third-party tools to plot or create a save for you. Saves using CGI will be deleted and you may receive a ban.\n"
"\bt7. Keep logos and signs to a minimum.\bw These saves may be removed from front page. Items that this rule restricts are:\n"
"- Excessive logos placed\n"
"- Signs without intended purpose\n"
"- Fake update or notifications signs\n"
"- Linking other saves that have no related purposes\n"
"\bt8. Do not place offtopic or inappropriate tags.\bw Tags are only there to improve search results. They should generally only be one word descriptions of the save. Sentences or subjective tags may be deleted. Inappropriate or offensive tags will likely get you banned.\n"
"\bt9. Intentional lag inducing or crashing saves are prohibited.\bw If the majority of users are writing about the save causing crashes or lag, then the save will fall under this rule. These saves will be removed from front page or disabled.\n"
"\bt10. Do not misuse the reporting system.\bw Sending in report reasons such as 'bad save' or gibberish wastes our time. Unless the issue pertains to a possible rule violation or community issue, please refrain from sending a report. If you think the save violates or poses a community issue, send a report anyway! Bans will never happen if you are reporting a save in good faith.\n"
"\bt11. Do not ask for saves to be demoted or removed from the front-page.\bw Unless the save violates any rules, it will stay on the front-page. There is no exception to this rule for art saves, please do not report art either.\n"
"\n"
"\boSection R: Other\n"
"\bwModerators may interpret these rules as they see fit. Not all rules are equal, some are enforced less than others. Moderators make the final decision on what is and isn't against the rules, but we have made our best effort here to cover all unwanted behavior here. Notice will be posted in this thread whenever the rules are updated.\n"
"\n"
"Violation of these rules may result in removal of posts / comments, unpublishing or disabling saves, removing saves from front page, or in more extreme cases, a temporary or permanent ban. There are various manual and automated measures in place to enforce these rules. The severity and resulting decisions may not be consistent between moderators.\n"
"\n"
"If you have any questions about what is and isn't against the rules, feel free to contact a moderator.";
}
};
Locale const &Locale_EN = LocaleEN{};

12
data/localization/List.h Normal file
View File

@ -0,0 +1,12 @@
#pragma once
#include <vector>
#include "common/Localization.h"
extern Locale const &Locale_EN;
const std::vector<Locale const *> locales =
{
&Locale_EN,
};

View File

@ -159,4 +159,60 @@
#define SDEUT
// Detailed build information string
#ifdef SNAPSHOT
#define SNAPSHOT_VER "SNAPSHOT " MTOS(SNAPSHOT_ID) " "
#elif MOD_ID > 0
#define SNAPSHOT_VER "MODVER " MTOS(SNAPSHOT_ID) " "
#else
#define SNAPSHOT_VER
#endif
#ifdef X86
#define HAVE_X86 "X86 "
#else
#define HAVE_X86 ""
#endif
#ifdef X86_SSE
#define HAVE_X86_SSE "X86_SSE "
#else
#define HAVE_X86_SSE ""
#endif
#ifdef X86_SSE2
#define HAVE_X86_SSE2 "X86_SSE2 "
#else
#define HAVE_X86_SSE2 ""
#endif
#ifdef X86_SSE3
#define HAVE_X86_SSE3 "X86_SSE3 "
#else
#define HAVE_X86_SSE3 ""
#endif
#ifdef LUACONSOLE
#define HAVE_LUACONSOLE "LUACONSOLE "
#else
#define HAVE_LUACONSOLE ""
#endif
#ifdef GRAVFFT
#define HAVE_GRAVFFT "GRAVFFT "
#else
#define HAVE_GRAVFFT ""
#endif
#ifdef REALISTIC
#define HAVE_REALISTIC "REALISTIC "
#else
#define HAVE_REALISTIC ""
#endif
#define BUILD_FLAVOR_STRING \
MTOS(SAVE_VERSION) "." MTOS(MINOR_VERSION) "." MTOS(BUILD_NUM) " " IDENT_PLATFORM " " \
SNAPSHOT_VER HAVE_X86 HAVE_X86_SSE HAVE_X86_SSE2 HAVE_X86_SSE3 HAVE_LUACONSOLE HAVE_GRAVFFT HAVE_REALISTIC
#endif /* CONFIG_H */

View File

@ -32,6 +32,8 @@
#include <sys/stat.h>
#endif
#include "localization/List.h"
#include "common/Internationalization.h"
#include "Format.h"
#include "Misc.h"
@ -483,11 +485,14 @@ void EventProcess(SDL_Event event)
void LargeScreenDialog()
{
auto switching = i18nMulti("Switching to ", "x size mode since your screen was determined to be large enough: ",
" detected, ", " required",
"\nTo undo this, hit Cancel. You can change this in settings at any time.");
StringBuilder message;
message << "Switching to " << scale << "x size mode since your screen was determined to be large enough: ";
message << desktopWidth << "x" << desktopHeight << " detected, " << WINDOWW*scale << "x" << WINDOWH*scale << " required";
message << "\nTo undo this, hit Cancel. You can change this in settings at any time.";
if (!ConfirmPrompt::Blocking("Large screen detected", message.Build()))
message << switching[0] << scale << switching[1];
message << desktopWidth << 'x' << desktopHeight << switching[2] << WINDOWW*scale << 'x' << WINDOWH*scale << switching[3];
message << switching[4];
if (!ConfirmPrompt::Blocking("Large screen detected"_i18n, message.Build()))
{
Client::Ref().SetPref("Scale", 1);
engine->SetScale(1);
@ -564,10 +569,10 @@ void BlueScreen(String detailMessage)
ui::Engine * engine = &ui::Engine::Ref();
engine->g->fillrect(0, 0, engine->GetWidth(), engine->GetHeight(), 17, 114, 169, 210);
String errorTitle = "ERROR";
String errorDetails = "Details: " + detailMessage;
String errorHelp = "An unrecoverable fault has occurred, please report the error by visiting the website below\n"
SCHEME SERVER;
String errorTitle = "ERROR"_i18n;
String errorDetails = "Details: "_i18n + detailMessage;
String errorHelp = "An unrecoverable fault has occurred, please report the error by visiting the website below\n"_i18n
+ ByteString(SCHEME SERVER).FromAscii();
int currentY = 0, width, height;
int errorWidth = 0;
Graphics::textsize(errorHelp, errorWidth, height);
@ -603,16 +608,16 @@ void SigHandler(int signal)
{
switch(signal){
case SIGSEGV:
BlueScreen("Memory read/write error");
BlueScreen("Memory read/write error"_i18n);
break;
case SIGFPE:
BlueScreen("Floating point exception");
BlueScreen("Floating point exception"_i18n);
break;
case SIGILL:
BlueScreen("Program execution exception");
BlueScreen("Program execution exception"_i18n);
break;
case SIGABRT:
BlueScreen("Unexpected program abort");
BlueScreen("Unexpected program abort"_i18n);
break;
}
}
@ -672,6 +677,23 @@ int main(int argc, char * argv[])
else
ChdirToDataDirectory();
#ifdef I18N_DEBUG
for(auto const &key : i18n::activeKeys())
{
std::cout << "{";
for(auto const &s : key)
std::cout << "\"" << s << "\",";
std::cout << "}" << std::endl;
}
#endif // I18N_DEBUG
String localeName = Client::Ref().GetPrefString("Locale", "");
currentLocale = locales[0];
for(Locale const *locale : locales)
if(locale->GetName() == localeName)
currentLocale = locale;
currentLocale->Set();
scale = Client::Ref().GetPrefInteger("Scale", 1);
resizable = Client::Ref().GetPrefBool("Resizable", false);
fullscreen = Client::Ref().GetPrefBool("Fullscreen", false);
@ -799,7 +821,7 @@ int main(int argc, char * argv[])
std::vector<unsigned char> gameSaveData = Client::Ref().ReadFile(arguments["open"]);
if(!gameSaveData.size())
{
new ErrorMessage("Error", "Could not read file");
new ErrorMessage("Error"_i18n, "Could not read file"_i18n);
}
else
{
@ -813,12 +835,12 @@ int main(int argc, char * argv[])
}
catch(std::exception & e)
{
new ErrorMessage("Error", "Could not open save file:\n" + ByteString(e.what()).FromUtf8()) ;
new ErrorMessage("Error"_i18n, "Could not open save file:\n"_i18n + ByteString(e.what()).FromUtf8()) ;
}
}
else
{
new ErrorMessage("Error", "Could not open file");
new ErrorMessage("Error"_i18n, "Could not open file"_i18n);
}
}
@ -826,7 +848,7 @@ int main(int argc, char * argv[])
{
engine->g->fillrect((engine->GetWidth()/2)-101, (engine->GetHeight()/2)-26, 202, 52, 0, 0, 0, 210);
engine->g->drawrect((engine->GetWidth()/2)-100, (engine->GetHeight()/2)-25, 200, 50, 255, 255, 255, 180);
engine->g->drawtext((engine->GetWidth()/2)-(Graphics::textwidth("Loading save...")/2), (engine->GetHeight()/2)-5, "Loading save...", style::Colour::InformationTitle.Red, style::Colour::InformationTitle.Green, style::Colour::InformationTitle.Blue, 255);
engine->g->drawtext((engine->GetWidth()/2)-(Graphics::textwidth("Loading save..."_i18n)/2), (engine->GetHeight()/2)-5, "Loading save..."_i18n, style::Colour::InformationTitle.Red, style::Colour::InformationTitle.Green, style::Colour::InformationTitle.Blue, 255);
#ifdef OGLI
blit();
@ -858,7 +880,7 @@ int main(int argc, char * argv[])
throw std::runtime_error("Could not load save info");
std::vector<unsigned char> saveData = Client::Ref().GetSaveData(saveId, 0);
if (!saveData.size())
throw std::runtime_error(("Could not load save\n" + Client::Ref().GetLastError()).ToUtf8());
throw std::runtime_error(("Could not load save\n"_i18n + Client::Ref().GetLastError()).ToUtf8());
GameSave * newGameSave = new GameSave(saveData);
newSave->SetGameSave(newGameSave);
@ -867,7 +889,7 @@ int main(int argc, char * argv[])
}
catch (std::exception & e)
{
new ErrorMessage("Error", ByteString(e.what()).FromUtf8());
new ErrorMessage("Error"_i18n, ByteString(e.what()).FromUtf8());
}
}

View File

@ -58,7 +58,7 @@ extern "C"
Client::Client():
messageOfTheDay("Fetching the message of the day..."),
messageOfTheDay("Fetching the message of the day..."_i18n),
versionCheckRequest(nullptr),
alternateVersionCheckRequest(nullptr),
usingAltUpdateServer(false),
@ -658,7 +658,8 @@ RequestStatus Client::ParseServerReturn(ByteString &result, int status, bool jso
return RequestOkay;
if (status != 200)
{
lastError = String::Build("HTTP Error ", status, ": ", http::StatusText(status));
auto errMsg = i18nMulti("HTTP Error ", ": ");
lastError = String::Build(errMsg[0], status, errMsg[1], http::StatusText(status));
return RequestFailure;
}
@ -687,11 +688,12 @@ RequestStatus Client::ParseServerReturn(ByteString &result, int status, bool jso
// sometimes the server returns a 200 with the text "Error: 401"
if (!strncmp(result.c_str(), "Error: ", 7))
{
auto errMsg = i18nMulti("HTTP Error ", ": ");
status = ByteString(result.begin() + 7, result.end()).ToNumber<int>();
lastError = String::Build("HTTP Error ", status, ": ", http::StatusText(status));
lastError = String::Build(errMsg[0], status, errMsg[1], http::StatusText(status));
return RequestFailure;
}
lastError = "Could not read response: " + ByteString(e.what()).FromUtf8();
lastError = "Could not read response: "_i18n + ByteString(e.what()).FromUtf8();
return RequestFailure;
}
}
@ -732,7 +734,10 @@ bool Client::CheckUpdate(http::Request *updateRequest, bool checkSession)
{
//free(data);
if (usingAltUpdateServer && !checkSession)
this->messageOfTheDay = String::Build("HTTP Error ", status, " while checking for updates: ", http::StatusText(status));
{
auto errMsg = i18nMulti("HTTP Error ", " while checking for updates: ");
this->messageOfTheDay = String::Build(errMsg[0], status, errMsg[1], http::StatusText(status));
}
}
else if(data.size())
{
@ -962,7 +967,7 @@ RequestStatus Client::UploadSave(SaveInfo & save)
{
if (!save.GetGameSave())
{
lastError = "Empty game save";
lastError = "Empty game save"_i18n;
return RequestFailure;
}
@ -972,13 +977,13 @@ RequestStatus Client::UploadSave(SaveInfo & save)
if (!gameData)
{
lastError = "Cannot serialize game save";
lastError = "Cannot serialize game save"_i18n;
return RequestFailure;
}
#if defined(SNAPSHOT) || defined(BETA) || defined(DEBUG)
else if (save.gameSave->fromNewerVersion)
{
lastError = "Cannot upload save, incompatible with latest release version";
lastError = "Cannot upload save, incompatible with latest release version"_i18n;
return RequestFailure;
}
#endif
@ -992,7 +997,7 @@ RequestStatus Client::UploadSave(SaveInfo & save)
}
else
{
lastError = "Not authenticated";
lastError = "Not authenticated"_i18n;
return RequestFailure;
}
@ -1002,7 +1007,7 @@ RequestStatus Client::UploadSave(SaveInfo & save)
int saveID = ByteString(data.begin() + 3, data.end()).ToNumber<int>();
if (!saveID)
{
lastError = "Server did not return Save ID";
lastError = "Server did not return Save ID"_i18n;
ret = RequestFailure;
}
else
@ -1176,7 +1181,7 @@ RequestStatus Client::ExecVote(int saveID, int direction)
}
else
{
lastError = "Not authenticated";
lastError = "Not authenticated"_i18n;
return RequestFailure;
}
RequestStatus ret = ParseServerReturn(data, dataStatus, false);
@ -1217,10 +1222,10 @@ LoginStatus Client::Login(ByteString username, ByteString password, User & user)
user.SessionKey = "";
//Doop
md5_ascii(passwordHash, (const unsigned char *)password.c_str(), password.length());
md5(passwordHash, (const unsigned char *)password.c_str(), password.length());
passwordHash[32] = 0;
ByteString total = ByteString::Build(username, "-", passwordHash);
md5_ascii(totalHash, (const unsigned char *)(total.c_str()), total.size());
md5(totalHash, (const unsigned char *)(total.c_str()), total.size());
totalHash[32] = 0;
ByteString data;
@ -1269,7 +1274,7 @@ LoginStatus Client::Login(ByteString username, ByteString password, User & user)
}
catch (std::exception &e)
{
lastError = "Could not read response: " + ByteString(e.what()).FromUtf8();
lastError = "Could not read response: "_i18n + ByteString(e.what()).FromUtf8();
return LoginError;
}
}
@ -1289,7 +1294,7 @@ RequestStatus Client::DeleteSave(int saveID)
}
else
{
lastError = "Not authenticated";
lastError = "Not authenticated"_i18n;
return RequestFailure;
}
RequestStatus ret = ParseServerReturn(data, dataStatus, true);
@ -1311,7 +1316,7 @@ RequestStatus Client::AddComment(int saveID, String comment)
}
else
{
lastError = "Not authenticated";
lastError = "Not authenticated"_i18n;
return RequestFailure;
}
RequestStatus ret = ParseServerReturn(data, dataStatus, true);
@ -1334,7 +1339,7 @@ RequestStatus Client::FavouriteSave(int saveID, bool favourite)
}
else
{
lastError = "Not authenticated";
lastError = "Not authenticated"_i18n;
return RequestFailure;
}
RequestStatus ret = ParseServerReturn(data, dataStatus, true);
@ -1356,7 +1361,7 @@ RequestStatus Client::ReportSave(int saveID, String message)
}
else
{
lastError = "Not authenticated";
lastError = "Not authenticated"_i18n;
return RequestFailure;
}
RequestStatus ret = ParseServerReturn(data, dataStatus, true);
@ -1376,7 +1381,7 @@ RequestStatus Client::UnpublishSave(int saveID)
}
else
{
lastError = "Not authenticated";
lastError = "Not authenticated"_i18n;
return RequestFailure;
}
RequestStatus ret = ParseServerReturn(data, dataStatus, true);
@ -1398,7 +1403,7 @@ RequestStatus Client::PublishSave(int saveID)
}
else
{
lastError = "Not authenticated";
lastError = "Not authenticated"_i18n;
return RequestFailure;
}
RequestStatus ret = ParseServerReturn(data, dataStatus, true);
@ -1465,7 +1470,7 @@ SaveInfo * Client::GetSave(int saveID, int saveDate)
}
catch (std::exception & e)
{
lastError = "Could not read response: " + ByteString(e.what()).FromUtf8();
lastError = "Could not read response: "_i18n + ByteString(e.what()).FromUtf8();
return NULL;
}
}
@ -1530,7 +1535,7 @@ std::vector<std::pair<ByteString, int> > * Client::GetTags(int start, int count,
}
catch (std::exception & e)
{
lastError = "Could not read response: " + ByteString(e.what()).FromUtf8();
lastError = "Could not read response: "_i18n + ByteString(e.what()).FromUtf8();
}
}
else
@ -1604,7 +1609,7 @@ std::vector<SaveInfo*> * Client::SearchSaves(int start, int count, String query,
}
catch (std::exception &e)
{
lastError = "Could not read response: " + ByteString(e.what()).FromUtf8();
lastError = "Could not read response: "_i18n + ByteString(e.what()).FromUtf8();
}
}
return saveArray;
@ -1624,7 +1629,7 @@ std::list<ByteString> * Client::RemoveTag(int saveID, ByteString tag)
}
else
{
lastError = "Not authenticated";
lastError = "Not authenticated"_i18n;
return NULL;
}
RequestStatus ret = ParseServerReturn(data, dataStatus, true);
@ -1643,7 +1648,7 @@ std::list<ByteString> * Client::RemoveTag(int saveID, ByteString tag)
}
catch (std::exception &e)
{
lastError = "Could not read response: " + ByteString(e.what()).FromUtf8();
lastError = "Could not read response: "_i18n + ByteString(e.what()).FromUtf8();
}
}
return tags;
@ -1663,7 +1668,7 @@ std::list<ByteString> * Client::AddTag(int saveID, ByteString tag)
}
else
{
lastError = "Not authenticated";
lastError = "Not authenticated"_i18n;
return NULL;
}
RequestStatus ret = ParseServerReturn(data, dataStatus, true);
@ -1682,7 +1687,7 @@ std::list<ByteString> * Client::AddTag(int saveID, ByteString tag)
}
catch (std::exception & e)
{
lastError = "Could not read response: " + ByteString(e.what()).FromUtf8();
lastError = "Could not read response: "_i18n + ByteString(e.what()).FromUtf8();
}
}
return tags;

View File

@ -212,18 +212,18 @@ void GameSave::read(char * data, int dataSize)
else if(data[0] == 'O' && data[1] == 'P' && data[2] == 'S')
{
if (data[3] != '1')
throw ParseException(ParseException::WrongVersion, "Save format from newer version");
throw ParseException(ParseException::WrongVersion, "Save format from newer version"_i18n);
readOPS(data, dataSize);
}
else
{
std::cerr << "Got Magic number '" << data[0] << data[1] << data[2] << "'" << std::endl;
throw ParseException(ParseException::Corrupt, "Invalid save format");
throw ParseException(ParseException::Corrupt, "Invalid save format"_i18n);
}
}
else
{
throw ParseException(ParseException::Corrupt, "No data");
throw ParseException(ParseException::Corrupt, "No data"_i18n);
}
}
@ -601,11 +601,11 @@ void GameSave::readOPS(char * data, int dataLength)
//Incompatible cell size
if (inputData[5] != CELL)
throw ParseException(ParseException::InvalidDimensions, "Incorrect CELL size");
throw ParseException(ParseException::InvalidDimensions, "Incorrect CELL size"_i18n);
//Too large/off screen
if (blockX+blockW > XRES/CELL || blockY+blockH > YRES/CELL)
throw ParseException(ParseException::InvalidDimensions, "Save too large");
throw ParseException(ParseException::InvalidDimensions, "Save too large"_i18n);
setSize(blockW, blockH);
@ -617,11 +617,11 @@ void GameSave::readOPS(char * data, int dataLength)
//Check for overflows, don't load saves larger than 200MB
unsigned int toAlloc = bsonDataLen+1;
if (toAlloc > 209715200 || !toAlloc)
throw ParseException(ParseException::InvalidDimensions, "Save data too large, refusing");
throw ParseException(ParseException::InvalidDimensions, "Save data too large, refusing"_i18n);
bsonData = (unsigned char*)malloc(toAlloc);
if (!bsonData)
throw ParseException(ParseException::InternalError, "Unable to allocate memory");
throw ParseException(ParseException::InternalError, "Unable to allocate memory"_i18n);
//Make sure bsonData is null terminated, since all string functions need null terminated strings
//(bson_iterator_key returns a pointer into bsonData, which is then used with strcmp)
@ -630,10 +630,11 @@ void GameSave::readOPS(char * data, int dataLength)
int bz2ret;
if ((bz2ret = BZ2_bzBuffToBuffDecompress((char*)bsonData, &bsonDataLen, (char*)(inputData+12), inputDataLen-12, 0, 0)) != BZ_OK)
{
throw ParseException(ParseException::Corrupt, String::Build("Unable to decompress (ret ", bz2ret, ")"));
auto decompress = i18nMulti("Unable to decompress (", ")");
throw ParseException(ParseException::Corrupt, String::Build(decompress[0], bz2ret, decompress[1]));
}
set_bson_err_handler([](const char* err) { throw ParseException(ParseException::Corrupt, "BSON error when parsing save: " + ByteString(err).FromUtf8()); });
set_bson_err_handler([](const char* err) { throw ParseException(ParseException::Corrupt, "BSON error when parsing save: "_i18n + ByteString(err).FromUtf8()); });
bson_init_data_size(&b, (char*)bsonData, bsonDataLen);
bson_iterator_init(&iter, &b);
@ -825,7 +826,7 @@ void GameSave::readOPS(char * data, int dataLength)
if (major > SAVE_VERSION || (major == SAVE_VERSION && minor > MINOR_VERSION))
#endif
{
String errorMessage = String::Build("Save from a newer version: Requires version ", major, ".", minor);
String errorMessage = String::Build("Save from a newer version: Requires version "_i18n, major, ".", minor);
throw ParseException(ParseException::WrongVersion, errorMessage);
}
#if defined(SNAPSHOT) || defined(DEBUG)
@ -861,7 +862,7 @@ void GameSave::readOPS(char * data, int dataLength)
{
unsigned int j = 0;
if (blockW * blockH > wallDataLen)
throw ParseException(ParseException::Corrupt, "Not enough wall data");
throw ParseException(ParseException::Corrupt, "Not enough wall data"_i18n);
for (unsigned int x = 0; x < blockW; x++)
{
for (unsigned int y = 0; y < blockH; y++)
@ -924,7 +925,7 @@ void GameSave::readOPS(char * data, int dataLength)
unsigned int j = 0;
unsigned char i, i2;
if (blockW * blockH > pressDataLen)
throw ParseException(ParseException::Corrupt, "Not enough pressure data");
throw ParseException(ParseException::Corrupt, "Not enough pressure data"_i18n);
for (unsigned int x = 0; x < blockW; x++)
{
for (unsigned int y = 0; y < blockH; y++)
@ -943,7 +944,7 @@ void GameSave::readOPS(char * data, int dataLength)
unsigned int j = 0;
unsigned char i, i2;
if (blockW * blockH > vxDataLen)
throw ParseException(ParseException::Corrupt, "Not enough vx data");
throw ParseException(ParseException::Corrupt, "Not enough vx data"_i18n);
for (unsigned int x = 0; x < blockW; x++)
{
for (unsigned int y = 0; y < blockH; y++)
@ -961,7 +962,7 @@ void GameSave::readOPS(char * data, int dataLength)
unsigned int j = 0;
unsigned char i, i2;
if (blockW * blockH > vyDataLen)
throw ParseException(ParseException::Corrupt, "Not enough vy data");
throw ParseException(ParseException::Corrupt, "Not enough vy data"_i18n);
for (unsigned int x = 0; x < blockW; x++)
{
for (unsigned int y = 0; y < blockH; y++)
@ -978,7 +979,7 @@ void GameSave::readOPS(char * data, int dataLength)
{
unsigned int i = 0, tempTemp;
if (blockW * blockH > ambientDataLen)
throw ParseException(ParseException::Corrupt, "Not enough ambient heat data");
throw ParseException(ParseException::Corrupt, "Not enough ambient heat data"_i18n);
for (unsigned int x = 0; x < blockW; x++)
{
for (unsigned int y = 0; y < blockH; y++)
@ -997,7 +998,7 @@ void GameSave::readOPS(char * data, int dataLength)
int newIndex = 0, fieldDescriptor, tempTemp;
int posCount, posTotal, partsPosDataIndex = 0;
if (fullW * fullH * 3 > partsPosDataLen)
throw ParseException(ParseException::Corrupt, "Not enough particle position data");
throw ParseException(ParseException::Corrupt, "Not enough particle position data"_i18n);
partsCount = 0;
@ -1019,16 +1020,16 @@ void GameSave::readOPS(char * data, int dataLength)
particlesCount = newIndex+1;
//i+3 because we have 4 bytes of required fields (type (1), descriptor (2), temp (1))
if (i+3 >= partsDataLen)
throw ParseException(ParseException::Corrupt, "Ran past particle data buffer");
throw ParseException(ParseException::Corrupt, "Ran past particle data buffer"_i18n);
x = saved_x + fullX;
y = saved_y + fullY;
fieldDescriptor = partsData[i+1];
fieldDescriptor |= partsData[i+2] << 8;
if (x >= fullW || y >= fullH)
throw ParseException(ParseException::Corrupt, "Particle out of range");
throw ParseException(ParseException::Corrupt, "Particle out of range"_i18n);
if (newIndex < 0 || newIndex >= NPART)
throw ParseException(ParseException::Corrupt, "Too many particles");
throw ParseException(ParseException::Corrupt, "Too many particles"_i18n);
//Clear the particle, ready for our new properties
memset(&(particles[newIndex]), 0, sizeof(Particle));
@ -1062,14 +1063,14 @@ void GameSave::readOPS(char * data, int dataLength)
if(fieldDescriptor & 0x02)
{
if (i >= partsDataLen)
throw ParseException(ParseException::Corrupt, "Ran past particle data buffer while loading life");
throw ParseException(ParseException::Corrupt, "Ran past particle data buffer while loading life"_i18n);
particles[newIndex].life = partsData[i++];
//i++;
//Read 2nd byte
if(fieldDescriptor & 0x04)
{
if (i >= partsDataLen)
throw ParseException(ParseException::Corrupt, "Ran past particle data buffer while loading life");
throw ParseException(ParseException::Corrupt, "Ran past particle data buffer while loading life"_i18n);
particles[newIndex].life |= (((unsigned)partsData[i++]) << 8);
}
}
@ -1078,19 +1079,19 @@ void GameSave::readOPS(char * data, int dataLength)
if(fieldDescriptor & 0x08)
{
if (i >= partsDataLen)
throw ParseException(ParseException::Corrupt, "Ran past particle data buffer while loading tmp");
throw ParseException(ParseException::Corrupt, "Ran past particle data buffer while loading tmp"_i18n);
particles[newIndex].tmp = partsData[i++];
//Read 2nd byte
if(fieldDescriptor & 0x10)
{
if (i >= partsDataLen)
throw ParseException(ParseException::Corrupt, "Ran past particle data buffer while loading tmp");
throw ParseException(ParseException::Corrupt, "Ran past particle data buffer while loading tmp"_i18n);
particles[newIndex].tmp |= (((unsigned)partsData[i++]) << 8);
//Read 3rd and 4th bytes
if(fieldDescriptor & 0x1000)
{
if (i+1 >= partsDataLen)
throw ParseException(ParseException::Corrupt, "Ran past particle data buffer while loading tmp");
throw ParseException(ParseException::Corrupt, "Ran past particle data buffer while loading tmp"_i18n);
particles[newIndex].tmp |= (((unsigned)partsData[i++]) << 24);
particles[newIndex].tmp |= (((unsigned)partsData[i++]) << 16);
}
@ -1101,13 +1102,13 @@ void GameSave::readOPS(char * data, int dataLength)
if(fieldDescriptor & 0x20)
{
if (i >= partsDataLen)
throw ParseException(ParseException::Corrupt, "Ran past particle data buffer while loading ctype");
throw ParseException(ParseException::Corrupt, "Ran past particle data buffer while loading ctype"_i18n);
particles[newIndex].ctype = partsData[i++];
//Read additional bytes
if(fieldDescriptor & 0x200)
{
if (i+2 >= partsDataLen)
throw ParseException(ParseException::Corrupt, "Ran past particle data buffer while loading ctype");
throw ParseException(ParseException::Corrupt, "Ran past particle data buffer while loading ctype"_i18n);
particles[newIndex].ctype |= (((unsigned)partsData[i++]) << 24);
particles[newIndex].ctype |= (((unsigned)partsData[i++]) << 16);
particles[newIndex].ctype |= (((unsigned)partsData[i++]) << 8);
@ -1118,7 +1119,7 @@ void GameSave::readOPS(char * data, int dataLength)
if(fieldDescriptor & 0x40)
{
if (i+3 >= partsDataLen)
throw ParseException(ParseException::Corrupt, "Ran past particle data buffer while loading deco");
throw ParseException(ParseException::Corrupt, "Ran past particle data buffer while loading deco"_i18n);
particles[newIndex].dcolour = (((unsigned)partsData[i++]) << 24);
particles[newIndex].dcolour |= (((unsigned)partsData[i++]) << 16);
particles[newIndex].dcolour |= (((unsigned)partsData[i++]) << 8);
@ -1129,7 +1130,7 @@ void GameSave::readOPS(char * data, int dataLength)
if(fieldDescriptor & 0x80)
{
if (i >= partsDataLen)
throw ParseException(ParseException::Corrupt, "Ran past particle data buffer while loading vx");
throw ParseException(ParseException::Corrupt, "Ran past particle data buffer while loading vx"_i18n);
particles[newIndex].vx = (partsData[i++]-127.0f)/16.0f;
}
@ -1137,7 +1138,7 @@ void GameSave::readOPS(char * data, int dataLength)
if(fieldDescriptor & 0x100)
{
if (i >= partsDataLen)
throw ParseException(ParseException::Corrupt, "Ran past particle data buffer while loading vy");
throw ParseException(ParseException::Corrupt, "Ran past particle data buffer while loading vy"_i18n);
particles[newIndex].vy = (partsData[i++]-127.0f)/16.0f;
}
@ -1145,12 +1146,12 @@ void GameSave::readOPS(char * data, int dataLength)
if(fieldDescriptor & 0x400)
{
if (i >= partsDataLen)
throw ParseException(ParseException::Corrupt, "Ran past particle data buffer while loading tmp2");
throw ParseException(ParseException::Corrupt, "Ran past particle data buffer while loading tmp2"_i18n);
particles[newIndex].tmp2 = partsData[i++];
if(fieldDescriptor & 0x800)
{
if (i >= partsDataLen)
throw ParseException(ParseException::Corrupt, "Ran past particle data buffer while loading tmp2");
throw ParseException(ParseException::Corrupt, "Ran past particle data buffer while loading tmp2"_i18n);
particles[newIndex].tmp2 |= (((unsigned)partsData[i++]) << 8);
}
}
@ -1159,7 +1160,7 @@ void GameSave::readOPS(char * data, int dataLength)
if(fieldDescriptor & 0x2000)
{
if (i+3 >= partsDataLen)
throw ParseException(ParseException::Corrupt, "Ran past particle data buffer while loading pavg");
throw ParseException(ParseException::Corrupt, "Ran past particle data buffer while loading pavg"_i18n);
int pavg;
pavg = partsData[i++];
pavg |= (((unsigned)partsData[i++]) << 8);
@ -1307,7 +1308,7 @@ void GameSave::readOPS(char * data, int dataLength)
}
if (i != partsDataLen)
throw ParseException(ParseException::Corrupt, "Didn't reach end of particle data buffer");
throw ParseException(ParseException::Corrupt, "Didn't reach end of particle data buffer"_i18n);
}
if (soapLinkData)
@ -1369,14 +1370,14 @@ void GameSave::readPSv(char * saveDataChar, int dataLength)
//This creates a problem for old clients, that display and "corrupt" error instead of a "newer version" error
if (dataLength<16)
throw ParseException(ParseException::Corrupt, "No save data");
throw ParseException(ParseException::Corrupt, "No save data"_i18n);
if (!(saveData[2]==0x43 && saveData[1]==0x75 && saveData[0]==0x66) && !(saveData[2]==0x76 && saveData[1]==0x53 && saveData[0]==0x50))
throw ParseException(ParseException::Corrupt, "Unknown format");
throw ParseException(ParseException::Corrupt, "Unknown format"_i18n);
if (saveData[2]==0x76 && saveData[1]==0x53 && saveData[0]==0x50) {
new_format = 1;
}
if (saveData[4]>SAVE_VERSION)
throw ParseException(ParseException::WrongVersion, "Save from newer version");
throw ParseException(ParseException::WrongVersion, "Save from newer version"_i18n);
ver = saveData[4];
majorVersion = saveData[4];
minorVersion = 0;
@ -1418,25 +1419,25 @@ void GameSave::readPSv(char * saveDataChar, int dataLength)
by0 = 0;
if (saveData[5]!=CELL || bx0+bw>XRES/CELL || by0+bh>YRES/CELL)
throw ParseException(ParseException::InvalidDimensions, "Save too large");
throw ParseException(ParseException::InvalidDimensions, "Save too large"_i18n);
int size = (unsigned)saveData[8];
size |= ((unsigned)saveData[9])<<8;
size |= ((unsigned)saveData[10])<<16;
size |= ((unsigned)saveData[11])<<24;
if (size > 209715200 || !size)
throw ParseException(ParseException::InvalidDimensions, "Save data too large");
throw ParseException(ParseException::InvalidDimensions, "Save data too large"_i18n);
auto dataPtr = std::unique_ptr<unsigned char[]>(new unsigned char[size]);
unsigned char *data = dataPtr.get();
if (!data)
throw ParseException(ParseException::Corrupt, "Cannot allocate memory");
throw ParseException(ParseException::Corrupt, "Cannot allocate memory"_i18n);
setSize(bw, bh);
int bzStatus = 0;
if ((bzStatus = BZ2_bzBuffToBuffDecompress((char *)data, (unsigned *)&size, (char *)(saveData+12), dataLength-12, 0, 0)))
throw ParseException(ParseException::Corrupt, String::Build("Cannot decompress: ", bzStatus));
throw ParseException(ParseException::Corrupt, String::Build("Cannot decompress: "_i18n, bzStatus));
dataLength = size;
#ifdef DEBUG
@ -1444,7 +1445,7 @@ void GameSave::readPSv(char * saveDataChar, int dataLength)
#endif
if (dataLength < bw*bh)
throw ParseException(ParseException::Corrupt, "Save data corrupt (missing data)");
throw ParseException(ParseException::Corrupt, "Save data corrupt (missing data)"_i18n);
// normalize coordinates
x0 = bx0*CELL;
@ -1461,7 +1462,7 @@ void GameSave::readPSv(char * saveDataChar, int dataLength)
int *particleIDMap = particleIDMapPtr.get();
std::fill(&particleIDMap[0], &particleIDMap[XRES*YRES], 0);
if (!particleIDMap)
throw ParseException(ParseException::Corrupt, "Cannot allocate memory");
throw ParseException(ParseException::Corrupt, "Cannot allocate memory"_i18n);
// load the required air state
for (y=by0; y<by0+bh; y++)
@ -1554,7 +1555,7 @@ void GameSave::readPSv(char * saveDataChar, int dataLength)
if (data[(y-by0)*bw+(x-bx0)]==4||(ver>=44 && data[(y-by0)*bw+(x-bx0)]==O_WL_FAN))
{
if (p >= dataLength)
throw ParseException(ParseException::Corrupt, "Not enough data at line " MTOS(__LINE__) " in " MTOS(__FILE__));
throw ParseException(ParseException::Corrupt, "Not enough data at "_i18n + ByteString(MTOS(__FILE__) ":" MTOS(__LINE__)).FromUtf8());
fanVelX[y][x] = (data[p++]-127.0f)/64.0f;
}
for (y=by0; y<by0+bh; y++)
@ -1562,7 +1563,7 @@ void GameSave::readPSv(char * saveDataChar, int dataLength)
if (data[(y-by0)*bw+(x-bx0)]==4||(ver>=44 && data[(y-by0)*bw+(x-bx0)]==O_WL_FAN))
{
if (p >= dataLength)
throw ParseException(ParseException::Corrupt, "Not enough data at line " MTOS(__LINE__) " in " MTOS(__FILE__));
throw ParseException(ParseException::Corrupt, "Not enough data at "_i18n + ByteString(MTOS(__FILE__) ":" MTOS(__LINE__)).FromUtf8());
fanVelY[y][x] = (data[p++]-127.0f)/64.0f;
}
@ -1574,10 +1575,10 @@ void GameSave::readPSv(char * saveDataChar, int dataLength)
for (x=x0; x<x0+w; x++)
{
if (p >= dataLength)
throw ParseException(ParseException::Corrupt, "Not enough data at line " MTOS(__LINE__) " in " MTOS(__FILE__));
throw ParseException(ParseException::Corrupt, "Not enough data at "_i18n + ByteString(MTOS(__FILE__) ":" MTOS(__LINE__)).FromUtf8());
j=data[p++];
if (j >= PT_NUM) {
j = PT_DUST;//throw ParseException(ParseException::Corrupt, "Not enough data at line " MTOS(__LINE__) " in " MTOS(__FILE__));
j = PT_DUST;//throw ParseException(ParseException::Corrupt, "Not enough data at "_i18n + ByteString(MTOS(__FILE__) ":" MTOS(__LINE__)).FromUtf8());
}
if (j)
{
@ -1608,7 +1609,7 @@ void GameSave::readPSv(char * saveDataChar, int dataLength)
{
i--;
if (p+1 >= dataLength)
throw ParseException(ParseException::Corrupt, "Not enough data at line " MTOS(__LINE__) " in " MTOS(__FILE__));
throw ParseException(ParseException::Corrupt, "Not enough data at "_i18n + ByteString(MTOS(__FILE__) ":" MTOS(__LINE__)).FromUtf8());
if (i < NPART)
{
particles[i].vx = (data[p++]-127.0f)/16.0f;
@ -1625,7 +1626,7 @@ void GameSave::readPSv(char * saveDataChar, int dataLength)
{
if (ver>=44) {
if (p >= dataLength) {
throw ParseException(ParseException::Corrupt, "Not enough data at line " MTOS(__LINE__) " in " MTOS(__FILE__));
throw ParseException(ParseException::Corrupt, "Not enough data at "_i18n + ByteString(MTOS(__FILE__) ":" MTOS(__LINE__)).FromUtf8());
}
if (i <= NPART) {
ttv = (data[p++])<<8;
@ -1636,7 +1637,7 @@ void GameSave::readPSv(char * saveDataChar, int dataLength)
}
} else {
if (p >= dataLength)
throw ParseException(ParseException::Corrupt, "Not enough data at line " MTOS(__LINE__) " in " MTOS(__FILE__));
throw ParseException(ParseException::Corrupt, "Not enough data at "_i18n + ByteString(MTOS(__FILE__) ":" MTOS(__LINE__)).FromUtf8());
if (i <= NPART)
particles[i-1].life = data[p++]*4;
else
@ -1651,7 +1652,7 @@ void GameSave::readPSv(char * saveDataChar, int dataLength)
if (i)
{
if (p >= dataLength) {
throw ParseException(ParseException::Corrupt, "Not enough data at line " MTOS(__LINE__) " in " MTOS(__FILE__));
throw ParseException(ParseException::Corrupt, "Not enough data at "_i18n + ByteString(MTOS(__FILE__) ":" MTOS(__LINE__)).FromUtf8());
}
if (i <= NPART) {
ttv = (data[p++])<<8;
@ -1681,7 +1682,7 @@ void GameSave::readPSv(char * saveDataChar, int dataLength)
if (i && (ty==PT_PBCN || (ty==PT_TRON && ver>=77)))
{
if (p >= dataLength)
throw ParseException(ParseException::Corrupt, "Not enough data at line " MTOS(__LINE__) " in " MTOS(__FILE__));
throw ParseException(ParseException::Corrupt, "Not enough data at "_i18n + ByteString(MTOS(__FILE__) ":" MTOS(__LINE__)).FromUtf8());
if (i <= NPART)
particles[i-1].tmp2 = data[p++];
else
@ -1697,7 +1698,7 @@ void GameSave::readPSv(char * saveDataChar, int dataLength)
{
if (ver>=49) {
if (p >= dataLength) {
throw ParseException(ParseException::Corrupt, "Not enough data at line " MTOS(__LINE__) " in " MTOS(__FILE__));
throw ParseException(ParseException::Corrupt, "Not enough data at "_i18n + ByteString(MTOS(__FILE__) ":" MTOS(__LINE__)).FromUtf8());
}
if (i <= NPART) {
particles[i-1].dcolour = data[p++]<<24;
@ -1715,7 +1716,7 @@ void GameSave::readPSv(char * saveDataChar, int dataLength)
{
if (ver>=49) {
if (p >= dataLength) {
throw ParseException(ParseException::Corrupt, "Not enough data at line " MTOS(__LINE__) " in " MTOS(__FILE__));
throw ParseException(ParseException::Corrupt, "Not enough data at "_i18n + ByteString(MTOS(__FILE__) ":" MTOS(__LINE__)).FromUtf8());
}
if (i <= NPART) {
particles[i-1].dcolour |= data[p++]<<16;
@ -1733,7 +1734,7 @@ void GameSave::readPSv(char * saveDataChar, int dataLength)
{
if (ver>=49) {
if (p >= dataLength) {
throw ParseException(ParseException::Corrupt, "Not enough data at line " MTOS(__LINE__) " in " MTOS(__FILE__));
throw ParseException(ParseException::Corrupt, "Not enough data at "_i18n + ByteString(MTOS(__FILE__) ":" MTOS(__LINE__)).FromUtf8());
}
if (i <= NPART) {
particles[i-1].dcolour |= data[p++]<<8;
@ -1751,7 +1752,7 @@ void GameSave::readPSv(char * saveDataChar, int dataLength)
{
if (ver>=49) {
if (p >= dataLength) {
throw ParseException(ParseException::Corrupt, "Not enough data at line " MTOS(__LINE__) " in " MTOS(__FILE__));
throw ParseException(ParseException::Corrupt, "Not enough data at "_i18n + ByteString(MTOS(__FILE__) ":" MTOS(__LINE__)).FromUtf8());
}
if (i <= NPART) {
particles[i-1].dcolour |= data[p++];
@ -1771,7 +1772,7 @@ void GameSave::readPSv(char * saveDataChar, int dataLength)
{
if (p >= dataLength)
{
throw ParseException(ParseException::Corrupt, "Not enough data at line " MTOS(__LINE__) " in " MTOS(__FILE__));
throw ParseException(ParseException::Corrupt, "Not enough data at "_i18n + ByteString(MTOS(__FILE__) ":" MTOS(__LINE__)).FromUtf8());
}
if (i <= NPART)
{
@ -1813,7 +1814,7 @@ void GameSave::readPSv(char * saveDataChar, int dataLength)
if (i && (ty==PT_CLNE || (ty==PT_PCLN && ver>=43) || (ty==PT_BCLN && ver>=44) || (ty==PT_SPRK && ver>=21) || (ty==PT_LAVA && ver>=34) || (ty==PT_PIPE && ver>=43) || (ty==PT_LIFE && ver>=51) || (ty==PT_PBCN && ver>=52) || (ty==PT_WIRE && ver>=55) || (ty==PT_STOR && ver>=59) || (ty==PT_CONV && ver>=60)))
{
if (p >= dataLength)
throw ParseException(ParseException::Corrupt, "Not enough data at line " MTOS(__LINE__) " in " MTOS(__FILE__));
throw ParseException(ParseException::Corrupt, "Not enough data at "_i18n + ByteString(MTOS(__FILE__) ":" MTOS(__LINE__)).FromUtf8());
if (i <= NPART)
particles[i-1].ctype = data[p++];
else
@ -1955,13 +1956,13 @@ void GameSave::readPSv(char * saveDataChar, int dataLength)
}
if (p >= dataLength)
throw ParseException(ParseException::Corrupt, "Ran past data buffer");
throw ParseException(ParseException::Corrupt, "Ran past data buffer"_i18n);
j = data[p++];
for (i=0; i<j; i++)
{
if (p+6 > dataLength)
throw ParseException(ParseException::Corrupt, "Not enough data at line " MTOS(__LINE__) " in " MTOS(__FILE__));
throw ParseException(ParseException::Corrupt, "Not enough data at "_i18n + ByteString(MTOS(__FILE__) ":" MTOS(__LINE__)).FromUtf8());
x = data[p++];
x |= ((unsigned)data[p++])<<8;
tempSign.x = x+x0;
@ -1972,7 +1973,7 @@ void GameSave::readPSv(char * saveDataChar, int dataLength)
tempSign.ju = (sign::Justification)x;
x = data[p++];
if (p+x > dataLength)
throw ParseException(ParseException::Corrupt, "Not enough data at line " MTOS(__LINE__) " in " MTOS(__FILE__));
throw ParseException(ParseException::Corrupt, "Not enough data at "_i18n + ByteString(MTOS(__FILE__) ":" MTOS(__LINE__)).FromUtf8());
if(x>254)
x = 254;
memcpy(tempSignText, data+p, x);
@ -2045,7 +2046,7 @@ char * GameSave::serialiseOPS(unsigned int & dataLength)
auto ambientData = std::unique_ptr<unsigned char[]>(new unsigned char[blockWidth*blockHeight*2]);
std::fill(&ambientData[0], &ambientData[blockWidth*blockHeight*2], 0);
if (!wallData || !fanData || !pressData || !vxData || !vyData || !ambientData)
throw BuildException("Save error, out of memory (blockmaps)");
throw BuildException("Save error, out of memory (blockmaps)"_i18n);
unsigned int wallDataLen = blockWidth*blockHeight, fanDataLen = 0, pressDataLen = 0, vxDataLen = 0, vyDataLen = 0, ambientDataLen = 0;
for (x = blockX; x < blockX+blockW; x++)
@ -2107,7 +2108,7 @@ char * GameSave::serialiseOPS(unsigned int & dataLength)
auto partsPosCount = std::unique_ptr<unsigned[]>(new unsigned[fullW*fullH]);
auto partsPosLink = std::unique_ptr<unsigned[]>(new unsigned[NPART]);
if (!partsPosFirstMap || !partsPosLastMap || !partsPosCount || !partsPosLink)
throw BuildException("Save error, out of memory (partmaps)");
throw BuildException("Save error, out of memory (partmaps)"_i18n);
std::fill(&partsPosFirstMap[0], &partsPosFirstMap[fullW*fullH], 0);
std::fill(&partsPosLastMap[0], &partsPosLastMap[fullW*fullH], 0);
std::fill(&partsPosCount[0], &partsPosCount[fullW*fullH], 0);
@ -2142,7 +2143,7 @@ char * GameSave::serialiseOPS(unsigned int & dataLength)
auto partsPosData = std::unique_ptr<unsigned char[]>(new unsigned char[fullW*fullH*3]);
unsigned int partsPosDataLen = 0;
if (!partsPosData)
throw BuildException("Save error, out of memory (partposdata)");
throw BuildException("Save error, out of memory (partposdata)"_i18n);
for (y=0;y<fullH;y++)
{
for (x=0;x<fullW;x++)
@ -2167,7 +2168,7 @@ char * GameSave::serialiseOPS(unsigned int & dataLength)
auto partsSaveIndex = std::unique_ptr<unsigned[]>(new unsigned[NPART]);
unsigned int partsCount = 0;
if (!partsData || !partsSaveIndex)
throw BuildException("Save error, out of memory (partsdata)");
throw BuildException("Save error, out of memory (partsdata)"_i18n);
std::fill(&partsSaveIndex[0], &partsSaveIndex[NPART], 0);
for (y=0;y<fullH;y++)
{
@ -2425,7 +2426,7 @@ char * GameSave::serialiseOPS(unsigned int & dataLength)
{
soapLinkData = new unsigned char[3*soapCount];
if (!soapLinkData)
throw BuildException("Save error, out of memory (SOAP)");
throw BuildException("Save error, out of memory (SOAP)"_i18n);
soapLinkDataPtr = std::unique_ptr<unsigned char[]>(soapLinkData);
//Iterate through particles in the same order that they were saved
@ -2484,7 +2485,7 @@ char * GameSave::serialiseOPS(unsigned int & dataLength)
// Use unique_ptr with a custom deleter to ensure that bson_destroy is called even when an exception is thrown
std::unique_ptr<bson, decltype(bson_deleter)> b_ptr(&b, bson_deleter);
set_bson_err_handler([](const char* err) { throw BuildException("BSON error when parsing save: " + ByteString(err).FromUtf8()); });
set_bson_err_handler([](const char* err) { throw BuildException("BSON error when parsing save: "_i18n + ByteString(err).FromUtf8()); });
bson_init(&b);
bson_append_start_object(&b, "origin");
bson_append_int(&b, "majorVersion", SAVE_VERSION);
@ -2605,13 +2606,13 @@ char * GameSave::serialiseOPS(unsigned int & dataLength)
bson_append_finish_object(&b);
}
if (bson_finish(&b) == BSON_ERROR)
throw BuildException("Error building bson data");
throw BuildException("Error building bson data"_i18n);
unsigned char *finalData = (unsigned char*)bson_data(&b);
unsigned int finalDataLen = bson_size(&b);
auto outputData = std::unique_ptr<unsigned char[]>(new unsigned char[finalDataLen*2+12]);
if (!outputData)
throw BuildException(String::Build("Save error, out of memory (finalData): ", finalDataLen*2+12));
throw BuildException(String::Build("Save error, out of memory (finalData): "_i18n, finalDataLen*2+12));
outputData[0] = 'O';
outputData[1] = 'P';
@ -2629,7 +2630,8 @@ char * GameSave::serialiseOPS(unsigned int & dataLength)
unsigned int compressedSize = finalDataLen*2, bz2ret;
if ((bz2ret = BZ2_bzBuffToBuffCompress((char*)(outputData.get()+12), &compressedSize, (char*)finalData, bson_size(&b), 9, 0, 0)) != BZ_OK)
{
throw BuildException(String::Build("Save error, could not compress (ret ", bz2ret, ")"));
auto compress = i18nMulti("Save error, could not compress (", ")");
throw BuildException(String::Build(compress[0], bz2ret, compress[1]));
}
#ifdef DEBUG

View File

@ -209,7 +209,7 @@ void md5_transform(unsigned buf[4], const unsigned char inraw[64])
}
static char hexChars[] = "0123456789abcdef";
void md5_ascii(char *result, unsigned char const *buf, unsigned len)
void md5(char *result, unsigned char const *buf, unsigned len)
{
struct md5_context md5;
unsigned char hash[16];

View File

@ -13,6 +13,6 @@ void md5_update(struct md5_context *context, unsigned char const *buf, unsigned
void md5_final(unsigned char digest[16], struct md5_context *context);
void md5_transform(unsigned buf[4], const unsigned char in[64]);
void md5_ascii(char *result, unsigned char const *buf, unsigned len);
void md5(char *result, unsigned char const *buf, unsigned len);
#endif

View File

@ -11,7 +11,7 @@ public:
ByteString username;
String biography;
String location;
ByteString website;
String website;
int saveCount;
float averageScore;
@ -21,7 +21,7 @@ public:
int topicReplies;
int reputation;
UserInfo(int id, int age, ByteString username, String biography, String location, ByteString website, int saveCount, float averageScore, int highestScore, int topicCount, int topicReplies, int reputation):
UserInfo(int id, int age, ByteString username, String biography, String location, String website, int saveCount, float averageScore, int highestScore, int topicCount, int topicReplies, int reputation):
UserID(id),
age(age),
username(username),

View File

@ -30,7 +30,7 @@ namespace http
user["Username"].asString(),
ByteString(user["Biography"].asString()).FromUtf8(),
ByteString(user["Location"].asString()).FromUtf8(),
user["Website"].asString(),
ByteString(user["Website"].asString()).FromUtf8(),
user["Saves"]["Count"].asInt(),
user["Saves"]["AverageScore"].asInt(),
user["Saves"]["HighestScore"].asInt(),

View File

@ -343,86 +343,86 @@ namespace http
{
switch (ret)
{
case 0: return "Status code 0 (bug?)";
case 100: return "Continue";
case 101: return "Switching Protocols";
case 102: return "Processing";
case 200: return "OK";
case 201: return "Created";
case 202: return "Accepted";
case 203: return "Non-Authoritative Information";
case 204: return "No Content";
case 205: return "Reset Content";
case 206: return "Partial Content";
case 207: return "Multi-Status";
case 300: return "Multiple Choices";
case 301: return "Moved Permanently";
case 302: return "Found";
case 303: return "See Other";
case 304: return "Not Modified";
case 305: return "Use Proxy";
case 306: return "Switch Proxy";
case 307: return "Temporary Redirect";
case 400: return "Bad Request";
case 401: return "Unauthorized";
case 402: return "Payment Required";
case 403: return "Forbidden";
case 404: return "Not Found";
case 405: return "Method Not Allowed";
case 406: return "Not Acceptable";
case 407: return "Proxy Authentication Required";
case 408: return "Request Timeout";
case 409: return "Conflict";
case 410: return "Gone";
case 411: return "Length Required";
case 412: return "Precondition Failed";
case 413: return "Request Entity Too Large";
case 414: return "Request URI Too Long";
case 415: return "Unsupported Media Type";
case 416: return "Requested Range Not Satisfiable";
case 417: return "Expectation Failed";
case 418: return "I'm a teapot";
case 422: return "Unprocessable Entity";
case 423: return "Locked";
case 424: return "Failed Dependency";
case 425: return "Unordered Collection";
case 426: return "Upgrade Required";
case 444: return "No Response";
case 450: return "Blocked by Windows Parental Controls";
case 499: return "Client Closed Request";
case 500: return "Internal Server Error";
case 501: return "Not Implemented";
case 502: return "Bad Gateway";
case 503: return "Service Unavailable";
case 504: return "Gateway Timeout";
case 505: return "HTTP Version Not Supported";
case 506: return "Variant Also Negotiates";
case 507: return "Insufficient Storage";
case 509: return "Bandwidth Limit Exceeded";
case 510: return "Not Extended";
case 600: return "Internal Client Error";
case 601: return "Unsupported Protocol";
case 602: return "Server Not Found";
case 603: return "Malformed Response";
case 604: return "Network Not Available";
case 605: return "Request Timed Out";
case 606: return "Malformed URL";
case 607: return "Connection Refused";
case 608: return "Proxy Server Not Found";
case 609: return "SSL: Invalid Certificate Status";
case 610: return "Cancelled by Shutdown";
case 611: return "Too Many Redirects";
case 612: return "SSL: Connect Error";
case 613: return "SSL: Crypto Engine Not Found";
case 614: return "SSL: Failed to Set Default Crypto Engine";
case 615: return "SSL: Local Certificate Issue";
case 616: return "SSL: Unable to Use Specified Cipher";
case 617: return "SSL: Failed to Initialise Crypto Engine";
case 618: return "SSL: Failed to Load CACERT File";
case 619: return "SSL: Failed to Load CRL File";
case 620: return "SSL: Issuer Check Failed";
case 621: return "SSL: Pinned Public Key Mismatch";
default: return "Unknown Status Code";
case 0: return "Status code 0 (bug?)"_i18n;
case 100: return "Continue"_i18n;
case 101: return "Switching Protocols"_i18n;
case 102: return "Processing"_i18n;
case 200: return "OK"_i18n;
case 201: return "Created"_i18n;
case 202: return "Accepted"_i18n;
case 203: return "Non-Authoritative Information"_i18n;
case 204: return "No Content"_i18n;
case 205: return "Reset Content"_i18n;
case 206: return "Partial Content"_i18n;
case 207: return "Multi-Status"_i18n;
case 300: return "Multiple Choices"_i18n;
case 301: return "Moved Permanently"_i18n;
case 302: return "Found"_i18n;
case 303: return "See Other"_i18n;
case 304: return "Not Modified"_i18n;
case 305: return "Use Proxy"_i18n;
case 306: return "Switch Proxy"_i18n;
case 307: return "Temporary Redirect"_i18n;
case 400: return "Bad Request"_i18n;
case 401: return "Unauthorized"_i18n;
case 402: return "Payment Required"_i18n;
case 403: return "Forbidden"_i18n;
case 404: return "Not Found"_i18n;
case 405: return "Method Not Allowed"_i18n;
case 406: return "Not Acceptable"_i18n;
case 407: return "Proxy Authentication Required"_i18n;
case 408: return "Request Timeout"_i18n;
case 409: return "Conflict"_i18n;
case 410: return "Gone"_i18n;
case 411: return "Length Required"_i18n;
case 412: return "Precondition Failed"_i18n;
case 413: return "Request Entity Too Large"_i18n;
case 414: return "Request URI Too Long"_i18n;
case 415: return "Unsupported Media Type"_i18n;
case 416: return "Requested Range Not Satisfiable"_i18n;
case 417: return "Expectation Failed"_i18n;
case 418: return "I'm a teapot"_i18n;
case 422: return "Unprocessable Entity"_i18n;
case 423: return "Locked"_i18n;
case 424: return "Failed Dependency"_i18n;
case 425: return "Unordered Collection"_i18n;
case 426: return "Upgrade Required"_i18n;
case 444: return "No Response"_i18n;
case 450: return "Blocked by Windows Parental Controls"_i18n;
case 499: return "Client Closed Request"_i18n;
case 500: return "Internal Server Error"_i18n;
case 501: return "Not Implemented"_i18n;
case 502: return "Bad Gateway"_i18n;
case 503: return "Service Unavailable"_i18n;
case 504: return "Gateway Timeout"_i18n;
case 505: return "HTTP Version Not Supported"_i18n;
case 506: return "Variant Also Negotiates"_i18n;
case 507: return "Insufficient Storage"_i18n;
case 509: return "Bandwidth Limit Exceeded"_i18n;
case 510: return "Not Extended"_i18n;
case 600: return "Internal Client Error"_i18n;
case 601: return "Unsupported Protocol"_i18n;
case 602: return "Server Not Found"_i18n;
case 603: return "Malformed Response"_i18n;
case 604: return "Network Not Available"_i18n;
case 605: return "Request Timed Out"_i18n;
case 606: return "Malformed URL"_i18n;
case 607: return "Connection Refused"_i18n;
case 608: return "Proxy Server Not Found"_i18n;
case 609: return "SSL: Invalid Certificate Status"_i18n;
case 610: return "Cancelled by Shutdown"_i18n;
case 611: return "Too Many Redirects"_i18n;
case 612: return "SSL: Connect Error"_i18n;
case 613: return "SSL: Crypto Engine Not Found"_i18n;
case 614: return "SSL: Failed to Set Default Crypto Engine"_i18n;
case 615: return "SSL: Local Certificate Issue"_i18n;
case 616: return "SSL: Unable to Use Specified Cipher"_i18n;
case 617: return "SSL: Failed to Initialise Crypto Engine"_i18n;
case 618: return "SSL: Failed to Load CACERT File"_i18n;
case 619: return "SSL: Failed to Load CRL File"_i18n;
case 620: return "SSL: Issuer Check Failed"_i18n;
case 621: return "SSL: Pinned Public Key Mismatch"_i18n;
default: return "Unknown Status Code"_i18n;
}
}
}

View File

@ -0,0 +1,47 @@
#include "Internationalization.h"
namespace i18n
{
// These are not global variables so that it is possible to use them during
// dynamic initialization of other global variables
static std::map<LiteralPtr, CanonicalPtr> &literalCanonicalization()
{
static std::map<LiteralPtr, CanonicalPtr> literalCanonicalization{};
return literalCanonicalization;
}
static std::map<ByteString, CanonicalPtr> &canonicalization()
{
static std::map<ByteString, CanonicalPtr> canonicalization{};
return canonicalization;
}
CanonicalPtr Canonicalize(LiteralPtr str)
{
auto it = literalCanonicalization().find(str);
if(it == literalCanonicalization().end())
{
CanonicalPtr can = canonicalization().insert(std::make_pair(str, str)).first->second;
literalCanonicalization().insert(std::make_pair(str, can));
return can;
}
else
return it->second;
}
#ifdef I18N_DEBUG
std::set<std::vector<ByteString> > &activeKeys()
{
static std::set<std::vector<ByteString> > activeKeys{};
return activeKeys;
}
std::set<ByteString> &activePlurals()
{
static std::set<ByteString> activePlurals{};
return activePlurals;
}
#endif // I18N_DEBUG
}
Locale const *currentLocale = nullptr;

View File

@ -0,0 +1,244 @@
#pragma once
#include <array>
#include <map>
#include <set>
#include <vector>
#include "String.h"
#include "Localization.h"
extern Locale const *currentLocale;
/*
We handle internationalization by maintaining a map from "key" strings, to
localized versions of those strings. The "keys" are strings in English, the
default language. At application startup this map is populated by
translations based on current settings. In theory this map could be updated
on the fly at runtime but various GUI interfaces will "cache" translations
of the strings that they use and working around this is tricky, thus we
require an application restart to change the language.
For performance reasons we rely on the assumption that we only need to
translate strings that are actual compile-time string literal constants.
Such literals are very easily equated by their pointer value: a pointer to a
string literal will always point to that literal and nothing else. The
LiteralPtr type is a pointer with this assumption.
However two instances of the same string literal might not have the same
pointer (in particular if the literal appears in different compilation
units; albeit depends on the compiler and compiler options). We thus
introduce another layer of indirection: a map from string literal pointers
to a "canonical" pointer for that string literal. Really it's just an
arbitrarily chosen literal pointer for that string. Invariant: given
CanonicalPtr c, LiteralPtr l, if !strcmp(l, c) then Canonicalize(l) == c.
Sometimes several pieces of strings are assembled into a larger string,
possibly with data inbetween, e.g.:
String::Build("Page ", page, " of ", total)
In the C world we could've gotten away with using a key with placeholders
such as "Page %d of %d" and then the translation would include the format
specifiers as well and it would all work out. Note that it is a bad idea to
introduce "Page" and "of" as separate keys as they don't make much sense on
their own. Our solution is to allow keys to be a *sequence* of English
strings that are intended to be used together, and the translation is a
sequence of the same length. In the above example our key would be
{"Page ", " of "}. We will then obtain a translation which would be a pair
of strings that could be fed into String::Build.
Sometimes the same English string is used in multiple places in different
contexts, and in a different language the different uses might require
different translations, e.g. "Login" could be a verb, or a noun. To remedy
this we can add a string to the key that would indicate the context, even
though the context part is never shown to the user, e.g.
{"Login", "Authenticate"} vs {"Login", "Username"}.
This interface boils down to a user-defined string literal operator""_i18n
that lets you write "Foo"_i18n which would look up translation for the key
"Foo" at runtime; and the function i18nMulti(...) which takes multiple keys
and returns an array of the same size with the translation of the entire
sequence.
*/
namespace i18n
{
using LiteralPtr = char const *;
using CanonicalPtr = char const *;
CanonicalPtr Canonicalize(LiteralPtr str);
#ifdef I18N_DEBUG
std::set<std::vector<ByteString> > &activeKeys();
std::set<ByteString> &activePlurals();
template<char... cs> struct Chars
{
static char const chars[];
};
template<char... cs> char const Chars<cs...>::chars[] = {cs..., 0};
template<char... cs> struct KeyUsage
{
KeyUsage() { activeKeys().insert({ByteString({cs..., 0})}); }
};
template<typename... Ts> struct MultiKeyUsage
{
MultiKeyUsage() { activeKeys().insert({Ts::chars...}); }
};
template<typename T> struct PluralUsage
{
PluralUsage() { activePlurals().insert(T::chars); }
};
template<char... cs> KeyUsage<cs...> keyUsage;
template<typename... Ts> MultiKeyUsage<Ts...> multiKeyUsage;
template<typename T> PluralUsage<T> pluralUsage;
#endif
template<size_t n> struct TranslationMap
{
// This is not just a static field so that it is possible to use it
// during dynamic initialization of global variables
static std::map<std::array<CanonicalPtr, n>, std::array<String, n>> &Map()
{
static std::map<std::array<CanonicalPtr, n>, std::array<String, n>> map{};
return map;
}
};
inline std::map<CanonicalPtr, std::vector<String>> &pluralForms()
{
static std::map<CanonicalPtr, std::vector<String>> pluralForms{};
return pluralForms;
}
template<size_t N> std::vector<String> &pluralForm(char const (&str)[N])
{
return pluralForms()[Canonicalize(str)];
}
template<size_t N> String &translation(char const (&str)[N])
{
return TranslationMap<1>::Map()[{Canonicalize(str)}][0];
}
template<size_t n> inline std::array<String, n> &multiTranslation(std::array<CanonicalPtr, n> &cans, size_t)
{
return TranslationMap<n>::Map()[cans];
}
template<size_t n, size_t N, typename... Ts> std::array<String, n> &multiTranslation(std::array<CanonicalPtr, n> &cans, size_t i, char const (&lit)[N], Ts&&... args)
{
cans[i] = Canonicalize(lit);
return multiTranslation(cans, i + 1, std::forward<Ts>(args)...);
}
template<typename... Ts> std::array<String, sizeof...(Ts)> &translation(Ts&&... args)
{
std::array<CanonicalPtr, sizeof...(Ts)> strs;
return multiTranslation(strs, 0, std::forward<Ts>(args)...);
}
template<size_t n> inline std::array<String, n> getTranslation(std::array<LiteralPtr, n> strs)
{
std::array<CanonicalPtr, n> cans;
for(size_t i = 0; i < n; i++)
cans[i] = Canonicalize(strs[i]);
auto it = TranslationMap<n>::Map().find(cans);
if(it != TranslationMap<n>::Map().end())
return it->second;
std::array<String, n> defs;
for(size_t i = 0; i < n; i++)
defs[i] = ByteString(strs[i]).FromAscii();
return defs;
}
template<size_t n> inline std::array<String, n> getMultiTranslation(std::array<LiteralPtr, n> &strs, size_t)
{
return getTranslation<n>(strs);
}
template<size_t n, size_t N, typename... Ts> std::array<String, n> getMultiTranslation(std::array<LiteralPtr, n> &strs, size_t i, char const (&lit)[N], Ts&&... args)
{
strs[i] = lit;
return getMultiTranslation(strs, i + 1, std::forward<Ts>(args)...);
}
inline String getPlural(LiteralPtr str, size_t n)
{
auto it = pluralForms().find(Canonicalize(str));
if(it == pluralForms().end() || !currentLocale)
return ByteString(str).FromUtf8();
return it->second[currentLocale->GetPluralIndex(n)];
}
}
#ifndef I18N_DEBUG
inline String operator""_i18n(char const *str, size_t)
{
return i18n::getTranslation<1>({str})[0];
}
template<typename... Ts> std::array<String, sizeof...(Ts)> i18nMulti(Ts&&... args)
{
std::array<i18n::LiteralPtr, sizeof...(Ts)> strs;
return i18n::getMultiTranslation(strs, 0, std::forward<Ts>(args)...);
}
inline String i18nPlural(char const *str, size_t n)
{
return i18n::getPlural(str, n);
}
#else // I18N_DEBUG
template<typename T, T... cs> inline i18n::Chars<cs...> operator""_chars()
{
return {};
}
template<typename T, T... cs> inline String operator""_i18n()
{
(void)i18n::keyUsage<cs...>;
return i18n::getTranslation<1>({i18n::Chars<cs...>::chars})[0];
}
// Macros are hard
// Expand i18nMulti("a", "b") into i18nMultiImpl<decltype("a"_chars), decltype("b"_chars)>()
#define NARG_SELECT(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, N, ...) N
#define NARG(...) NARG_SELECT(__VA_ARGS__, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
#define i18nMultiNargH(N, ...) i18nMultiNarg(N, __VA_ARGS__)
#define i18nMultiNarg(N, ...) i18nMulti_##N(__VA_ARGS__)
#define i18nMulti(...) i18nMultiNargH(NARG(__VA_ARGS__), __VA_ARGS__)
#define i18nMulti_1(s1) i18nMultiImpl<decltype(s1##_chars)>()
#define i18nMulti_2(s1, s2) i18nMultiImpl<decltype(s1##_chars), decltype(s2##_chars)>()
#define i18nMulti_3(s1, s2, s3) i18nMultiImpl<decltype(s1##_chars), decltype(s2##_chars), decltype(s3##_chars)>()
#define i18nMulti_4(s1, s2, s3, s4) i18nMultiImpl<decltype(s1##_chars), decltype(s2##_chars), decltype(s3##_chars), decltype(s4##_chars)>()
#define i18nMulti_5(s1, s2, s3, s4, s5) i18nMultiImpl<decltype(s1##_chars), decltype(s2##_chars), decltype(s3##_chars), decltype(s4##_chars), decltype(s5##_chars)>()
#define i18nMulti_6(s1, s2, s3, s4, s5, s6) i18nMultiImpl<decltype(s1##_chars), decltype(s2##_chars), decltype(s3##_chars), decltype(s4##_chars), decltype(s5##_chars), decltype(s6##_chars)>()
#define i18nMulti_7(s1, s2, s3, s4, s5, s6, s7) i18nMultiImpl<decltype(s1##_chars), decltype(s2##_chars), decltype(s3##_chars), decltype(s4##_chars), decltype(s5##_chars), decltype(s6##_chars), decltype(s7##_chars)>()
#define i18nMulti_8(s1, s2, s3, s4, s5, s6, s7, s8) i18nMultiImpl<decltype(s1##_chars), decltype(s2##_chars), decltype(s3##_chars), decltype(s4##_chars), decltype(s5##_chars), decltype(s6##_chars), decltype(s7##_chars), decltype(s8##_chars)>()
#define i18nMulti_9(s1, s2, s3, s4, s5, s6, s7, s8, s9) i18nMultiImpl<decltype(s1##_chars), decltype(s2##_chars), decltype(s3##_chars), decltype(s4##_chars), decltype(s5##_chars), decltype(s6##_chars), decltype(s7##_chars), decltype(s8##_chars), decltype(s9##_chars)>()
#define i18nMulti_10(s1, s2, s3, s4, s5, s6, s7, s8, s9, s10) i18nMultiImpl<decltype(s1##_chars), decltype(s2##_chars), decltype(s3##_chars), decltype(s4##_chars), decltype(s5##_chars), decltype(s6##_chars), decltype(s7##_chars), decltype(s8##_chars), decltype(s9##_chars), decltype(s10##_chars)>()
#define i18nMulti_11(s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11) i18nMultiImpl<decltype(s1##_chars), decltype(s2##_chars), decltype(s3##_chars), decltype(s4##_chars), decltype(s5##_chars), decltype(s6##_chars), decltype(s7##_chars), decltype(s8##_chars), decltype(s9##_chars), decltype(s10##_chars), decltype(s11##_chars)>()
#define i18nMulti_12(s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12) i18nMultiImpl<decltype(s1##_chars), decltype(s2##_chars), decltype(s3##_chars), decltype(s4##_chars), decltype(s5##_chars), decltype(s6##_chars), decltype(s7##_chars), decltype(s8##_chars), decltype(s9##_chars), decltype(s10##_chars), decltype(s11##_chars), decltype(s12##_chars)>()
template<typename... Ts> std::array<String, sizeof...(Ts)> i18nMultiImpl()
{
(void)i18n::multiKeyUsage<Ts...>;
std::array<i18n::LiteralPtr, sizeof...(Ts)> strs;
return i18n::getMultiTranslation(strs, 0, Ts::chars...);
}
#define i18nPlural(str, n) i18nPluralImpl<decltype(str##_chars)>(n)
template<typename T> String i18nPluralImpl(size_t n)
{
(void)i18n::pluralUsage<T>;
return i18n::getPlural(T::chars, n);
}
#endif // I18N_DEBUG

39
src/common/Localization.h Normal file
View File

@ -0,0 +1,39 @@
#pragma once
#include <functional>
struct Locale
{
// The name of the language this locale is for, readable in both the native
// language and in English;
virtual class String GetName() const = 0;
// Populate the translations map.
virtual void Set() const = 0;
virtual class String GetIntroText() const = 0;
virtual class String GetSavePublishingInfo() const = 0;
virtual class String GetRules() const = 0;
/*
English only has two choices for spelling a noun based on amount:
singular when there's exactly 1 object, and plural when there's 0 or 2
or more objects.
In Russian there are three choices, based on the last 2 digits of the
amount: singular nominative if the number ends in 1, except 11;
singular genitive if the number ends in 2,3,4, except 12 through 14;
plural genitive if the for everything else.
In other languages things can get more complicated, for example in
Arabic a noun can have as many as 6 spellings.
What we can do is give these various forms indices, e.g. for Russian
singular nominative=0, singular genitive=1, plural genitive=2;
and then use these indices to index into an array of spellings for the
respective word.
GetPluralIndex(n) returns the index of the word form used for n objects.
*/
virtual size_t GetPluralIndex(size_t n) const = 0;
};

View File

@ -293,7 +293,7 @@ inline wchar_t narrow_wchar(String::value_type ch)
char const numberChars[] = "-.+0123456789ABCDEFXabcdefx";
ByteString numberByteString(numberChars);
String numberString(numberChars);
String numberString(numberByteString.FromAscii());
struct LocaleImpl
{

View File

@ -683,3 +683,4 @@ template<typename... Ts> String String::Build(Ts&&... args)
}
#include "common/Format.h"
#include "common/Internationalization.h"

View File

@ -18,7 +18,7 @@ void DebugParts::Draw()
Graphics * g = ui::Engine::Ref().g;
int x = 0, y = 0, lpx = 0, lpy = 0;
String info = String::Build(sim->parts_lastActiveIndex, "/", NPART, " (", Format::Precision((float)sim->parts_lastActiveIndex/(NPART)*100.0f, 2), "%)");
String info = String::Build(sim->parts_lastActiveIndex, '/', NPART, " (", Format::Precision((float)sim->parts_lastActiveIndex/(NPART)*100.0f, 2), "%)");
for (int i = 0; i < NPART; i++)
{
if (sim->parts[i].type)

View File

@ -26,19 +26,23 @@ void ParticleDebug::Debug(int mode, int x, int y)
while (i < NPART && !sim->parts[i].type)
i++;
if (i == NPART)
logmessage = "End of particles reached, updated sim";
logmessage = "End of particles reached, updated sim"_i18n;
else
logmessage = String::Build("Updated particle #", i);
logmessage = String::Build("Updated particle #"_i18n, i);
}
else if (mode == 1)
{
if (x < 0 || x >= XRES || y < 0 || y >= YRES || !sim->pmap[y][x] || (i = ID(sim->pmap[y][x])) < debug_currentParticle)
{
i = NPART;
logmessage = String::Build("Updated particles from #", debug_currentParticle, " to end, updated sim");
auto updated = i18nMulti("Updated particles from #", " to end, updated sim");
logmessage = String::Build(updated[0], debug_currentParticle, updated[1]);
}
else
logmessage = String::Build("Updated particles #", debug_currentParticle, " through #", i);
{
auto updated = i18nMulti("Updated particles #", "through #");
logmessage = String::Build(updated[0], debug_currentParticle, updated[1], i);
}
}
model->Log(logmessage, false);
@ -90,7 +94,8 @@ bool ParticleDebug::KeyPress(int key, int scan, bool shift, bool ctrl, bool alt,
{
sim->UpdateParticles(sim->debug_currentParticle, NPART);
sim->AfterSim();
String logmessage = String::Build("Updated particles from #", sim->debug_currentParticle, " to end, updated sim");
auto updated = i18nMulti("Updated particles from #", " to end, updated sim");
String logmessage = String::Build(updated[0], sim->debug_currentParticle, updated[1]);
model->Log(logmessage, false);
sim->debug_currentParticle = 0;
}

View File

@ -734,6 +734,7 @@ void Graphics::textsize(String str, int & width, int & height)
void Graphics::draw_icon(int x, int y, Icon icon, unsigned char alpha, bool invert)
{
static String voteText = "Vote"_i18n;
y--;
switch(icon)
{
@ -759,12 +760,12 @@ void Graphics::draw_icon(int x, int y, Icon icon, unsigned char alpha, bool inve
if(invert)
{
drawchar(x-11, y+1, 0xE04B, 0, 100, 0, alpha);
drawtext(x+2, y+1, "Vote", 0, 100, 0, alpha);
drawtext(x+2, y+1, voteText, 0, 100, 0, alpha);
}
else
{
drawchar(x-11, y+1, 0xE04B, 0, 187, 18, alpha);
drawtext(x+2, y+1, "Vote", 0, 187, 18, alpha);
drawtext(x+2, y+1, voteText, 0, 187, 18, alpha);
}
break;
case IconVoteDown:

View File

@ -2587,67 +2587,67 @@ Renderer::Renderer(Graphics * g, Simulation * sim):
//Render mode presets. Possibly load from config in future?
renderModePresets.push_back({
"Alternative Velocity Display",
"Alternative Velocity Display"_i18n,
{ RENDER_EFFE, RENDER_BASC },
{ DISPLAY_AIRC },
0
});
renderModePresets.push_back({
"Velocity Display",
"Velocity Display"_i18n,
{ RENDER_EFFE, RENDER_BASC },
{ DISPLAY_AIRV },
0
});
renderModePresets.push_back({
"Pressure Display",
"Pressure Display"_i18n,
{ RENDER_EFFE, RENDER_BASC },
{ DISPLAY_AIRP },
0
});
renderModePresets.push_back({
"Persistent Display",
"Persistent Display"_i18n,
{ RENDER_EFFE, RENDER_BASC },
{ DISPLAY_PERS },
0
});
renderModePresets.push_back({
"Fire Display",
"Fire Display"_i18n,
{ RENDER_FIRE, RENDER_SPRK, RENDER_EFFE, RENDER_BASC },
{ },
0
});
renderModePresets.push_back({
"Blob Display",
"Blob Display"_i18n,
{ RENDER_FIRE, RENDER_SPRK, RENDER_EFFE, RENDER_BLOB },
{ },
0
});
renderModePresets.push_back({
"Heat Display",
"Heat Display"_i18n,
{ RENDER_BASC },
{ DISPLAY_AIRH },
COLOUR_HEAT
});
renderModePresets.push_back({
"Fancy Display",
"Fancy Display"_i18n,
{ RENDER_FIRE, RENDER_SPRK, RENDER_GLOW, RENDER_BLUR, RENDER_EFFE, RENDER_BASC },
{ DISPLAY_WARP },
0
});
renderModePresets.push_back({
"Nothing Display",
"Nothing Display"_i18n,
{ RENDER_BASC },
{ },
0
});
renderModePresets.push_back({
"Heat Gradient Display",
"Heat Gradient Display"_i18n,
{ RENDER_BASC },
{ },
COLOUR_GRAD
});
renderModePresets.push_back({
"Life Gradient Display",
"Life Gradient Display"_i18n,
{ RENDER_BASC },
{ },
COLOUR_LIFE

View File

@ -66,7 +66,7 @@ ColourPickerActivity::ColourPickerActivity(ui::Colour initialColour, OnPicked on
hexValue = new::ui::Label(ui::Point(150, Size.Y-23), ui::Point(53, 17), "0xFFFFFFFF");
AddComponent(hexValue);
ui::Button * doneButton = new ui::Button(ui::Point(Size.X-45, Size.Y-23), ui::Point(40, 17), "Done");
ui::Button * doneButton = new ui::Button(ui::Point(Size.X-45, Size.Y-23), ui::Point(40, 17), "Done"_i18n);
doneButton->SetActionCallback({ [this] {
int Red, Green, Blue;
Red = rValue->GetText().ToNumber<int>(true);

View File

@ -38,7 +38,7 @@ ConfirmPrompt::ConfirmPrompt(String title, String message, ResultCallback callba
Size.Y += messagePanel->Size.Y+12;
Position.Y = (ui::Engine::Ref().GetHeight()-Size.Y)/2;
ui::Button * cancelButton = new ui::Button(ui::Point(0, Size.Y-16), ui::Point(Size.X-75, 16), "Cancel");
ui::Button * cancelButton = new ui::Button(ui::Point(0, Size.Y-16), ui::Point(Size.X-75, 16), "Cancel"_i18n);
cancelButton->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
cancelButton->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
cancelButton->Appearance.BorderInactive = ui::Colour(200, 200, 200);

View File

@ -15,10 +15,10 @@ class ConfirmPrompt : public ui::Window
ResultCallback callback;
public:
ConfirmPrompt(String title, String message, ResultCallback callback_ = {}, String buttonText = String("Confirm"));
ConfirmPrompt(String title, String message, ResultCallback callback_ = {}, String buttonText = "Confirm"_i18n);
virtual ~ConfirmPrompt() = default;
static bool Blocking(String title, String message, String buttonText = String("Confirm"));
static bool Blocking(String title, String message, String buttonText = "Confirm"_i18n);
void OnDraw() override;
};

View File

@ -29,7 +29,7 @@ ErrorMessage::ErrorMessage(String title, String message, DismissCallback callbac
Size.Y += messageLabel->Size.Y+12;
Position.Y = (ui::Engine::Ref().GetHeight()-Size.Y)/2;
ui::Button * okayButton = new ui::Button(ui::Point(0, Size.Y-16), ui::Point(Size.X, 16), "Dismiss");
ui::Button * okayButton = new ui::Button(ui::Point(0, Size.Y-16), ui::Point(Size.X, 16), "Dismiss"_i18n);
okayButton->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
okayButton->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
okayButton->Appearance.BorderInactive = ui::Colour(200, 200, 200);

View File

@ -55,7 +55,7 @@ InformationMessage::InformationMessage(String title, String message, bool large)
titleLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
AddComponent(titleLabel);
ui::Button * okayButton = new ui::Button(ui::Point(0, Size.Y-16), ui::Point(Size.X, 16), "Dismiss");
ui::Button * okayButton = new ui::Button(ui::Point(0, Size.Y-16), ui::Point(Size.X, 16), "Dismiss"_i18n);
okayButton->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
okayButton->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
okayButton->Appearance.BorderInactive = ui::Colour(200, 200, 200);

View File

@ -13,21 +13,21 @@
SaveIDMessage::SaveIDMessage(int id):
ui::Window(ui::Point((XRES-244)/2, (YRES-90)/2), ui::Point(244, 90))
{
int textWidth = Graphics::textwidth("Save ID");
ui::Label * titleLabel = new ui::Label(ui::Point(4, 5), ui::Point(textWidth+20, 16), "Save ID");
int textWidth = Graphics::textwidth("Save ID"_i18n);
ui::Label * titleLabel = new ui::Label(ui::Point(4, 5), ui::Point(textWidth+20, 16), "Save ID"_i18n);
titleLabel->SetTextColour(style::Colour::InformationTitle);
titleLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
titleLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
AddComponent(titleLabel);
textWidth = Graphics::textwidth("Saved Successfully!");
ui::Label * messageLabel = new ui::Label(ui::Point(4, 24), ui::Point(textWidth+20, 16), "Saved Successfully!");
textWidth = Graphics::textwidth("Saved Successfully!"_i18n);
ui::Label * messageLabel = new ui::Label(ui::Point(4, 24), ui::Point(textWidth+20, 16), "Saved Successfully!"_i18n);
messageLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
messageLabel->Appearance.VerticalAlign = ui::Appearance::AlignTop;
AddComponent(messageLabel);
textWidth = Graphics::textwidth("Click the box below to copy the save ID");
ui::Label * copyTextLabel = new ui::Label(ui::Point((Size.X-textWidth-20)/2, 35), ui::Point(textWidth+20, 16), "Click the box below to copy the save id");
textWidth = Graphics::textwidth("Click the box below to copy the save ID"_i18n);
ui::Label * copyTextLabel = new ui::Label(ui::Point((Size.X-textWidth-20)/2, 35), ui::Point(textWidth+20, 16), "Click the box below to copy the save id"_i18n);
copyTextLabel->SetTextColour(ui::Colour(150, 150, 150));
copyTextLabel->Appearance.HorizontalAlign = ui::Appearance::AlignCentre;
AddComponent(copyTextLabel);
@ -36,7 +36,7 @@ SaveIDMessage::SaveIDMessage(int id):
ui::CopyTextButton * copyTextButton = new ui::CopyTextButton(ui::Point((Size.X-textWidth-10)/2, 50), ui::Point(textWidth+10, 18), String::Build(id), copyTextLabel);
AddComponent(copyTextButton);
ui::Button * okayButton = new ui::Button(ui::Point(0, Size.Y-16), ui::Point(Size.X, 16), "OK");
ui::Button * okayButton = new ui::Button(ui::Point(0, Size.Y-16), ui::Point(Size.X, 16), "OK"_i18n);
okayButton->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
okayButton->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
okayButton->SetActionCallback({ [this] {

View File

@ -47,7 +47,7 @@ TextPrompt::TextPrompt(String title, String message, String text, String placeho
AddComponent(textField);
FocusComponent(textField);
ui::Button * cancelButton = new ui::Button(ui::Point(0, Size.Y-16), ui::Point((Size.X/2)+1, 16), "Cancel");
ui::Button * cancelButton = new ui::Button(ui::Point(0, Size.Y-16), ui::Point((Size.X/2)+1, 16), "Cancel"_i18n);
cancelButton->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
cancelButton->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
cancelButton->Appearance.BorderInactive = ui::Colour(200, 200, 200);
@ -60,7 +60,7 @@ TextPrompt::TextPrompt(String title, String message, String text, String placeho
AddComponent(cancelButton);
SetCancelButton(cancelButton);
ui::Button * okayButton = new ui::Button(ui::Point(Size.X/2, Size.Y-16), ui::Point(Size.X/2, 16), "Okay");
ui::Button * okayButton = new ui::Button(ui::Point(Size.X/2, Size.Y-16), ui::Point(Size.X/2, 16), "OK"_i18n);
okayButton->Appearance.HorizontalAlign = ui::Appearance::AlignRight;
okayButton->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
okayButton->Appearance.TextInactive = style::Colour::WarningTitle;

View File

@ -28,7 +28,7 @@ ElementSearchActivity::ElementSearchActivity(GameController * gameController, st
isToolTipFadingIn(false),
exit(false)
{
ui::Label * title = new ui::Label(ui::Point(4, 5), ui::Point(Size.X-8, 15), "Element Search");
ui::Label * title = new ui::Label(ui::Point(4, 5), ui::Point(Size.X-8, 15), "Element Search"_i18n);
title->SetTextColour(style::Colour::InformationTitle);
title->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
AddComponent(title);
@ -39,9 +39,9 @@ ElementSearchActivity::ElementSearchActivity(GameController * gameController, st
AddComponent(searchField);
FocusComponent(searchField);
ui::Button * closeButton = new ui::Button(ui::Point(0, Size.Y-15), ui::Point((Size.X/2)+1, 15), "Close");
ui::Button * closeButton = new ui::Button(ui::Point(0, Size.Y-15), ui::Point((Size.X/2)+1, 15), "Close"_i18n);
closeButton->SetActionCallback({ [this] { exit = true; } });
ui::Button * okButton = new ui::Button(ui::Point(Size.X/2, Size.Y-15), ui::Point(Size.X/2, 15), "OK");
ui::Button * okButton = new ui::Button(ui::Point(Size.X/2, Size.Y-15), ui::Point(Size.X/2, 15), "OK"_i18n);
okButton->SetActionCallback({ [this] {
if (GetFirstResult())
SetActiveTool(0, GetFirstResult());

View File

@ -87,13 +87,13 @@ FileBrowserActivity::FileBrowserActivity(ByteString directory, OnSelected onSele
totalFiles(0)
{
ui::Label * titleLabel = new ui::Label(ui::Point(4, 5), ui::Point(Size.X-8, 18), "Save Browser");
ui::Label * titleLabel = new ui::Label(ui::Point(4, 5), ui::Point(Size.X-8, 18), "Save Browser"_i18n);
titleLabel->SetTextColour(style::Colour::WarningTitle);
titleLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
titleLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
AddComponent(titleLabel);
ui::Textbox * textField = new ui::Textbox(ui::Point(8, 25), ui::Point(Size.X-16, 16), "", "[search]");
ui::Textbox * textField = new ui::Textbox(ui::Point(8, 25), ui::Point(Size.X-16, 16), "", "[search]"_i18n);
textField->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
textField->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
textField->SetActionCallback({ [this, textField] { DoSearch(textField->GetText().ToUtf8()); } });
@ -107,7 +107,7 @@ FileBrowserActivity::FileBrowserActivity(ByteString directory, OnSelected onSele
progressBar = new ui::ProgressBar(ui::Point((Size.X-200)/2, 45+(Size.Y-66)/2), ui::Point(200, 17));
AddComponent(progressBar);
infoText = new ui::Label(ui::Point((Size.X-200)/2, 45+(Size.Y-66)/2), ui::Point(200, 17), "No saves found");
infoText = new ui::Label(ui::Point((Size.X-200)/2, 45+(Size.Y-66)/2), ui::Point(200, 17), "No saves found"_i18n);
AddComponent(infoText);
filesX = 4;
@ -143,8 +143,9 @@ void FileBrowserActivity::SelectSave(SaveFile * file)
void FileBrowserActivity::DeleteSave(SaveFile * file)
{
String deleteMessage = "Are you sure you want to delete " + file->GetDisplayName() + ".cps?";
if (ConfirmPrompt::Blocking("Delete Save", deleteMessage))
auto deleteConfirm = i18nMulti("Are you sure you want to delete ", "?");
String deleteMessage = deleteConfirm[0] + file->GetDisplayName() + ".cps" + deleteConfirm[1];
if (ConfirmPrompt::Blocking("Delete Save"_i18n, deleteMessage))
{
remove(file->GetName().c_str());
loadDirectory(directory, "");
@ -153,18 +154,18 @@ void FileBrowserActivity::DeleteSave(SaveFile * file)
void FileBrowserActivity::RenameSave(SaveFile * file)
{
ByteString newName = TextPrompt::Blocking("Rename", "Change save name", file->GetDisplayName(), "", 0).ToUtf8();
ByteString newName = TextPrompt::Blocking("Rename"_i18n, "Change save name"_i18n, file->GetDisplayName(), "", 0).ToUtf8();
if (newName.length())
{
newName = directory + PATH_SEP + newName + ".cps";
int ret = rename(file->GetName().c_str(), newName.c_str());
if (ret)
ErrorMessage::Blocking("Error", "Could not rename file");
ErrorMessage::Blocking("Error"_i18n, "Could not rename file"_i18n);
else
loadDirectory(directory, "");
}
else
ErrorMessage::Blocking("Error", "No save name given");
ErrorMessage::Blocking("Error"_i18n, "No save name given"_i18n);
}
void FileBrowserActivity::cleanup()
@ -196,7 +197,7 @@ void FileBrowserActivity::loadDirectory(ByteString directory, ByteString search)
itemList->Visible = false;
progressBar->Visible = true;
progressBar->SetProgress(-1);
progressBar->SetStatus("Loading files");
progressBar->SetStatus("Loading files"_i18n);
loadFiles = new LoadFilesTask(directory, search);
loadFiles->AddTaskListener(this);
loadFiles->Start();
@ -280,7 +281,7 @@ void FileBrowserActivity::OnTick(float dt)
[this, saveButton] { DeleteSave(saveButton->GetSaveFile()); }
});
progressBar->SetStatus("Rendering thumbnails");
progressBar->SetStatus("Rendering thumbnails"_i18n);
progressBar->SetProgress((float(totalFiles-files.size())/float(totalFiles))*100.0f);
componentsQueue.push_back(saveButton);
fileX++;

View File

@ -295,20 +295,20 @@ void GameController::PlaceSave(ui::Point position)
void GameController::Install()
{
#if defined(MACOSX)
new InformationMessage("No installation necessary", "You don't need to install The Powder Toy on OS X", false);
new InformationMessage("No installation necessary"_i18n, "You don't need to install The Powder Toy on OS X"_i18n, false);
#elif defined(WIN) || defined(LIN)
new ConfirmPrompt("Install The Powder Toy", "Do you wish to install The Powder Toy on this computer?\nThis allows you to open save files and saves directly from the website.", { [] {
new ConfirmPrompt("Install The Powder Toy"_i18n, "Do you wish to install The Powder Toy on this computer?\nThis allows you to open save files and saves directly from the website."_i18n, { [] {
if (Client::Ref().DoInstallation())
{
new InformationMessage("Success", "Installation completed", false);
new InformationMessage("Success"_i18n, "Installation completed"_i18n, false);
}
else
{
new ErrorMessage("Could not install", "The installation did not complete due to an error");
new ErrorMessage("Could not install"_i18n, "The installation did not complete due to an error"_i18n);
}
} });
#else
new ErrorMessage("Cannot install", "You cannot install The Powder Toy on this platform");
new ErrorMessage("Cannot install"_i18n, "You cannot install The Powder Toy on this platform"_i18n);
#endif
}
@ -519,12 +519,12 @@ ByteString GameController::StampRegion(ui::Point point1, ui::Point point2)
ByteString stampName = Client::Ref().AddStamp(newSave);
delete newSave;
if (stampName.length() == 0)
new ErrorMessage("Could not create stamp", "Error serializing save file");
new ErrorMessage("Could not create stamp"_i18n, "Error serializing save file"_i18n);
return stampName;
}
else
{
new ErrorMessage("Could not create stamp", "Error generating save file");
new ErrorMessage("Could not create stamp"_i18n, "Error generating save file"_i18n);
return "";
}
}
@ -840,13 +840,13 @@ void GameController::SwitchGravity()
switch (gameModel->GetSimulation()->gravityMode)
{
case 0:
gameModel->SetInfoTip("Gravity: Vertical");
gameModel->SetInfoTip("Gravity: Vertical"_i18n);
break;
case 1:
gameModel->SetInfoTip("Gravity: Off");
gameModel->SetInfoTip("Gravity: Off"_i18n);
break;
case 2:
gameModel->SetInfoTip("Gravity: Radial");
gameModel->SetInfoTip("Gravity: Radial"_i18n);
break;
}
}
@ -858,19 +858,19 @@ void GameController::SwitchAir()
switch (gameModel->GetSimulation()->air->airMode)
{
case 0:
gameModel->SetInfoTip("Air: On");
gameModel->SetInfoTip("Air: On"_i18n);
break;
case 1:
gameModel->SetInfoTip("Air: Pressure Off");
gameModel->SetInfoTip("Air: Pressure Off"_i18n);
break;
case 2:
gameModel->SetInfoTip("Air: Velocity Off");
gameModel->SetInfoTip("Air: Velocity Off"_i18n);
break;
case 3:
gameModel->SetInfoTip("Air: Off");
gameModel->SetInfoTip("Air: Off"_i18n);
break;
case 4:
gameModel->SetInfoTip("Air: No Update");
gameModel->SetInfoTip("Air: No Update"_i18n);
break;
}
}
@ -1164,7 +1164,7 @@ void GameController::OpenSearch(String searchText)
}
catch(GameModelException & ex)
{
new ErrorMessage("Cannot open save", ByteString(ex.what()).FromUtf8());
new ErrorMessage("Cannot open save"_i18n, ByteString(ex.what()).FromUtf8());
}
}
});
@ -1179,7 +1179,7 @@ void GameController::OpenLocalSaveWindow(bool asCurrent)
GameSave * gameSave = sim->Save(gameModel->GetIncludePressure() != gameView->ShiftBehaviour());
if(!gameSave)
{
new ErrorMessage("Error", "Unable to build save.");
new ErrorMessage("Error"_i18n, "Unable to build save."_i18n);
}
else
{
@ -1213,11 +1213,11 @@ void GameController::OpenLocalSaveWindow(bool asCurrent)
Client::Ref().MakeDirectory(LOCAL_SAVE_DIR);
std::vector<char> saveData = gameSave->Serialise();
if (saveData.size() == 0)
new ErrorMessage("Error", "Unable to serialize game data.");
new ErrorMessage("Error"_i18n, "Unable to serialize game data."_i18n);
else if (Client::Ref().WriteFile(saveData, gameModel->GetSaveFile()->GetName()))
new ErrorMessage("Error", "Unable to write save file.");
new ErrorMessage("Error"_i18n, "Unable to write save file."_i18n);
else
gameModel->SetInfoTip("Saved Successfully");
gameModel->SetInfoTip("Saved Successfully"_i18n);
}
}
}
@ -1244,7 +1244,7 @@ void GameController::OpenSaveDone()
}
catch(GameModelException & ex)
{
new ErrorMessage("Cannot open save", ByteString(ex.what()).FromUtf8());
new ErrorMessage("Cannot open save"_i18n, ByteString(ex.what()).FromUtf8());
}
}
}
@ -1326,7 +1326,7 @@ void GameController::OpenTags()
}
else
{
new ErrorMessage("Error", "No save open");
new ErrorMessage("Error"_i18n, "No save open"_i18n);
}
}
@ -1337,7 +1337,7 @@ void GameController::OpenStamps()
if (file)
{
if (file->GetError().length())
new ErrorMessage("Error loading stamp", file->GetError());
new ErrorMessage("Error loading stamp"_i18n, file->GetError());
else if (localBrowser->GetMoveToFront())
Client::Ref().MoveStampToFront(file->GetDisplayName().ToUtf8());
LoadStamp(file->GetGameSave());
@ -1385,7 +1385,7 @@ void GameController::OpenSaveWindow()
GameSave * gameSave = sim->Save(gameModel->GetIncludePressure() != gameView->ShiftBehaviour());
if(!gameSave)
{
new ErrorMessage("Error", "Unable to build save.");
new ErrorMessage("Error"_i18n, "Unable to build save."_i18n);
}
else
{
@ -1415,7 +1415,7 @@ void GameController::OpenSaveWindow()
}
else
{
new ErrorMessage("Error", "You need to login to upload saves.");
new ErrorMessage("Error"_i18n, "You need to login to upload saves."_i18n);
}
}
@ -1427,7 +1427,7 @@ void GameController::SaveAsCurrent()
GameSave * gameSave = sim->Save(gameModel->GetIncludePressure() != gameView->ShiftBehaviour());
if(!gameSave)
{
new ErrorMessage("Error", "Unable to build save.");
new ErrorMessage("Error"_i18n, "Unable to build save."_i18n);
}
else
{
@ -1453,7 +1453,7 @@ void GameController::SaveAsCurrent()
}
else
{
new ErrorMessage("Error", "You need to login to upload saves.");
new ErrorMessage("Error"_i18n, "You need to login to upload saves."_i18n);
}
}
@ -1473,7 +1473,7 @@ void GameController::Vote(int direction)
}
catch(GameModelException & ex)
{
new ErrorMessage("Error while voting", ByteString(ex.what()).FromUtf8());
new ErrorMessage("Error while voting"_i18n, ByteString(ex.what()).FromUtf8());
}
}
}
@ -1584,37 +1584,37 @@ void GameController::NotifyUpdateAvailable(Client * sender)
UpdateInfo info = Client::Ref().GetUpdateInfo();
StringBuilder updateMessage;
#ifndef MACOSX
updateMessage << "Are you sure you want to run the updater? Please save any changes before updating.\n\nCurrent version:\n ";
updateMessage << "Are you sure you want to run the updater? Please save any changes before updating.\n\nCurrent version:\n "_i18n;
#else
updateMessage << "Click \"Continue\" to download the latest version from our website.\n\nCurrent version:\n ";
updateMessage << "Click \"Continue\" to download the latest version from our website.\n\nCurrent version:\n "_i18n;
#endif
#ifdef SNAPSHOT
updateMessage << "Snapshot " << SNAPSHOT_ID;
updateMessage << "Snapshot "_i18n << SNAPSHOT_ID;
#elif MOD_ID > 0
updateMessage << "Mod version " << SNAPSHOT_ID;
updateMessage << "Mod version "_i18n << SNAPSHOT_ID;
#elif defined(BETA)
updateMessage << SAVE_VERSION << "." << MINOR_VERSION << " Beta, Build " << BUILD_NUM;
updateMessage << SAVE_VERSION << '.' << MINOR_VERSION << " Beta, Build "_i18n << BUILD_NUM;
#else
updateMessage << SAVE_VERSION << "." << MINOR_VERSION << " Stable, Build " << BUILD_NUM;
updateMessage << SAVE_VERSION << '.' << MINOR_VERSION << " Stable, Build "_i18n << BUILD_NUM;
#endif
updateMessage << "\nNew version:\n ";
updateMessage << "\nNew version:\n "_i18n;
if (info.Type == UpdateInfo::Beta)
updateMessage << info.Major << "." << info.Minor << " Beta, Build " << info.Build;
updateMessage << info.Major << '.' << info.Minor << " Beta, Build "_i18n << info.Build;
else if (info.Type == UpdateInfo::Snapshot)
#if MOD_ID > 0
updateMessage << "Mod version " << info.Time;
updateMessage << "Mod version "_i18n << info.Time;
#else
updateMessage << "Snapshot " << info.Time;
updateMessage << "Snapshot "_i18n << info.Time;
#endif
else if(info.Type == UpdateInfo::Stable)
updateMessage << info.Major << "." << info.Minor << " Stable, Build " << info.Build;
updateMessage << info.Major << '.' << info.Minor << " Stable, Build "_i18n << info.Build;
if (info.Changelog.length())
updateMessage << "\n\nChangelog:\n" << info.Changelog;
updateMessage << "\n\nChangelog:\n"_i18n << info.Changelog;
new ConfirmPrompt("Run Updater", updateMessage.Build(), { [this] { c->RunUpdater(); } });
new ConfirmPrompt("Run Updater"_i18n, updateMessage.Build(), { [this] { c->RunUpdater(); } });
}
};
@ -1622,16 +1622,16 @@ void GameController::NotifyUpdateAvailable(Client * sender)
{
case UpdateInfo::Snapshot:
#if MOD_ID > 0
gameModel->AddNotification(new UpdateNotification(this, "A new mod update is available - click here to update"));
gameModel->AddNotification(new UpdateNotification(this, "A new mod update is available - click here to update"_i18n));
#else
gameModel->AddNotification(new UpdateNotification(this, "A new snapshot is available - click here to update"));
gameModel->AddNotification(new UpdateNotification(this, "A new snapshot is available - click here to update"_i18n));
#endif
break;
case UpdateInfo::Stable:
gameModel->AddNotification(new UpdateNotification(this, "A new version is available - click here to update"));
gameModel->AddNotification(new UpdateNotification(this, "A new version is available - click here to update"_i18n));
break;
case UpdateInfo::Beta:
gameModel->AddNotification(new UpdateNotification(this, "A new beta is available - click here to update"));
gameModel->AddNotification(new UpdateNotification(this, "A new beta is available - click here to update"_i18n));
break;
}
}

View File

@ -330,19 +330,19 @@ void GameModel::BuildMenus()
menuList[SC_TOOL]->AddTool(tempTool);
}
//Add special sign and prop tools
menuList[SC_TOOL]->AddTool(new WindTool(0, "WIND", "Creates air movement.", 64, 64, 64, "DEFAULT_UI_WIND"));
menuList[SC_TOOL]->AddTool(new WindTool(0, "WIND", "Creates air movement."_i18n, 64, 64, 64, "DEFAULT_UI_WIND"));
menuList[SC_TOOL]->AddTool(new PropertyTool());
menuList[SC_TOOL]->AddTool(new SignTool(this));
menuList[SC_TOOL]->AddTool(new SampleTool(this));
//Add decoration tools to menu
menuList[SC_DECO]->AddTool(new DecorationTool(ren, DECO_ADD, "ADD", "Colour blending: Add.", 0, 0, 0, "DEFAULT_DECOR_ADD"));
menuList[SC_DECO]->AddTool(new DecorationTool(ren, DECO_SUBTRACT, "SUB", "Colour blending: Subtract.", 0, 0, 0, "DEFAULT_DECOR_SUB"));
menuList[SC_DECO]->AddTool(new DecorationTool(ren, DECO_MULTIPLY, "MUL", "Colour blending: Multiply.", 0, 0, 0, "DEFAULT_DECOR_MUL"));
menuList[SC_DECO]->AddTool(new DecorationTool(ren, DECO_DIVIDE, "DIV", "Colour blending: Divide." , 0, 0, 0, "DEFAULT_DECOR_DIV"));
menuList[SC_DECO]->AddTool(new DecorationTool(ren, DECO_SMUDGE, "SMDG", "Smudge tool, blends surrounding deco together.", 0, 0, 0, "DEFAULT_DECOR_SMDG"));
menuList[SC_DECO]->AddTool(new DecorationTool(ren, DECO_CLEAR, "CLR", "Erase any set decoration.", 0, 0, 0, "DEFAULT_DECOR_CLR"));
menuList[SC_DECO]->AddTool(new DecorationTool(ren, DECO_DRAW, "SET", "Draw decoration (No blending).", 0, 0, 0, "DEFAULT_DECOR_SET"));
menuList[SC_DECO]->AddTool(new DecorationTool(ren, DECO_ADD, "ADD", "Colour blending: Add."_i18n, 0, 0, 0, "DEFAULT_DECOR_ADD"));
menuList[SC_DECO]->AddTool(new DecorationTool(ren, DECO_SUBTRACT, "SUB", "Colour blending: Subtract."_i18n, 0, 0, 0, "DEFAULT_DECOR_SUB"));
menuList[SC_DECO]->AddTool(new DecorationTool(ren, DECO_MULTIPLY, "MUL", "Colour blending: Multiply."_i18n, 0, 0, 0, "DEFAULT_DECOR_MUL"));
menuList[SC_DECO]->AddTool(new DecorationTool(ren, DECO_DIVIDE, "DIV", "Colour blending: Divide."_i18n , 0, 0, 0, "DEFAULT_DECOR_DIV"));
menuList[SC_DECO]->AddTool(new DecorationTool(ren, DECO_SMUDGE, "SMDG", "Smudge tool, blends surrounding deco together."_i18n, 0, 0, 0, "DEFAULT_DECOR_SMDG"));
menuList[SC_DECO]->AddTool(new DecorationTool(ren, DECO_CLEAR, "CLR", "Erase any set decoration."_i18n, 0, 0, 0, "DEFAULT_DECOR_CLR"));
menuList[SC_DECO]->AddTool(new DecorationTool(ren, DECO_DRAW, "SET", "Draw decoration (No blending)."_i18n, 0, 0, 0, "DEFAULT_DECOR_SET"));
SetColourSelectorColour(colour); // update tool colors
decoToolset[0] = GetToolFromIdentifier("DEFAULT_DECOR_SET");
decoToolset[1] = GetToolFromIdentifier("DEFAULT_DECOR_CLR");
@ -542,7 +542,7 @@ void GameModel::SetVote(int direction)
}
else
{
throw GameModelException("Could not vote: "+Client::Ref().GetLastError());
throw GameModelException("Could not vote: "_i18n+Client::Ref().GetLastError());
}
}
}
@ -968,7 +968,8 @@ void GameModel::SetPaused(bool pauseState)
{
if (!pauseState && sim->debug_currentParticle > 0)
{
String logmessage = String::Build("Updated particles from #", sim->debug_currentParticle, " to end due to unpause");
auto updated = i18nMulti("Updated particles from #", " to end due to unpause");
String logmessage = String::Build(updated[0], sim->debug_currentParticle, updated[1]);
sim->UpdateParticles(sim->debug_currentParticle, NPART);
sim->AfterSim();
sim->debug_currentParticle = 0;
@ -992,9 +993,9 @@ void GameModel::SetDecoration(bool decorationState)
notifyDecorationChanged();
UpdateQuickOptions();
if (decorationState)
SetInfoTip("Decorations Layer: On");
SetInfoTip("Decorations Layer: On"_i18n);
else
SetInfoTip("Decorations Layer: Off");
SetInfoTip("Decorations Layer: Off"_i18n);
}
}
@ -1008,9 +1009,9 @@ void GameModel::SetAHeatEnable(bool aHeat)
sim->aheat_enable = aHeat;
UpdateQuickOptions();
if (aHeat)
SetInfoTip("Ambient Heat: On");
SetInfoTip("Ambient Heat: On"_i18n);
else
SetInfoTip("Ambient Heat: Off");
SetInfoTip("Ambient Heat: Off"_i18n);
}
bool GameModel::GetAHeatEnable()
@ -1023,12 +1024,12 @@ void GameModel::SetNewtonianGravity(bool newtonainGravity)
if (newtonainGravity)
{
sim->grav->start_grav_async();
SetInfoTip("Newtonian Gravity: On");
SetInfoTip("Newtonian Gravity: On"_i18n);
}
else
{
sim->grav->stop_grav_async();
SetInfoTip("Newtonian Gravity: Off");
SetInfoTip("Newtonian Gravity: Off"_i18n);
}
UpdateQuickOptions();
}
@ -1042,9 +1043,9 @@ void GameModel::ShowGravityGrid(bool showGrid)
{
ren->gravityFieldEnabled = showGrid;
if (showGrid)
SetInfoTip("Gravity Grid: On");
SetInfoTip("Gravity Grid: On"_i18n);
else
SetInfoTip("Gravity Grid: Off");
SetInfoTip("Gravity Grid: Off"_i18n);
}
bool GameModel::GetGravityGrid()

View File

@ -10,7 +10,6 @@
#include "Notification.h"
#include "Brush.h"
#include "IntroText.h"
#include "QuickOptions.h"
#include "DecorationTool.h"
#include "ToolButton.h"
@ -190,7 +189,7 @@ GameView::GameView():
buttonTip(""),
isButtonTipFadingIn(false),
introText(2048),
introTextMessage(ByteString(introTextData).FromUtf8()),
introTextMessage(currentLocale->GetIntroText() + "\n\bt" BUILD_FLAVOR_STRING ""),
doScreenshot(false),
screenshotIndex(0),
@ -224,7 +223,7 @@ GameView::GameView():
scrollBar->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
AddComponent(scrollBar);
searchButton = new ui::Button(ui::Point(currentX, Size.Y-16), ui::Point(17, 15), "", "Find & open a simulation. Hold Ctrl to load offline saves."); //Open
searchButton = new ui::Button(ui::Point(currentX, Size.Y-16), ui::Point(17, 15), "", "Find & open a simulation. Hold Ctrl to load offline saves."_i18n); //Open
searchButton->SetIcon(IconOpen);
currentX+=18;
searchButton->SetTogglable(false);
@ -236,14 +235,14 @@ GameView::GameView():
} });
AddComponent(searchButton);
reloadButton = new ui::Button(ui::Point(currentX, Size.Y-16), ui::Point(17, 15), "", "Reload the simulation");
reloadButton = new ui::Button(ui::Point(currentX, Size.Y-16), ui::Point(17, 15), "", "Reload the simulation"_i18n);
reloadButton->SetIcon(IconReload);
reloadButton->Appearance.Margin.Left+=2;
currentX+=18;
reloadButton->SetActionCallback({ [this] { c->ReloadSim(); }, [this] { c->OpenSavePreview(); } });
AddComponent(reloadButton);
saveSimulationButton = new SplitButton(ui::Point(currentX, Size.Y-16), ui::Point(150, 15), "[untitled simulation]", "", "", 19);
saveSimulationButton = new SplitButton(ui::Point(currentX, Size.Y-16), ui::Point(150, 15), "[untitled simulation]"_i18n, "", "", 19);
saveSimulationButton->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
saveSimulationButton->SetIcon(IconSave);
currentX+=151;
@ -264,7 +263,7 @@ GameView::GameView():
SetSaveButtonTooltips();
AddComponent(saveSimulationButton);
upVoteButton = new ui::Button(ui::Point(currentX, Size.Y-16), ui::Point(39, 15), "", "Like this save");
upVoteButton = new ui::Button(ui::Point(currentX, Size.Y-16), ui::Point(39, 15), "", "Like this save"_i18n);
upVoteButton->SetIcon(IconVoteUp);
upVoteButton->Appearance.Margin.Top+=2;
upVoteButton->Appearance.Margin.Left+=2;
@ -272,7 +271,7 @@ GameView::GameView():
upVoteButton->SetActionCallback({ [this] { c->Vote(1); } });
AddComponent(upVoteButton);
downVoteButton = new ui::Button(ui::Point(currentX, Size.Y-16), ui::Point(15, 15), "", "Dislike this save");
downVoteButton = new ui::Button(ui::Point(currentX, Size.Y-16), ui::Point(15, 15), "", "Dislike this save"_i18n);
downVoteButton->SetIcon(IconVoteDown);
downVoteButton->Appearance.Margin.Bottom+=2;
downVoteButton->Appearance.Margin.Left+=2;
@ -280,20 +279,20 @@ GameView::GameView():
downVoteButton->SetActionCallback({ [this] { c->Vote(-1); } });
AddComponent(downVoteButton);
tagSimulationButton = new ui::Button(ui::Point(currentX, Size.Y-16), ui::Point(227, 15), "[no tags set]", "Add simulation tags");
tagSimulationButton = new ui::Button(ui::Point(currentX, Size.Y-16), ui::Point(227, 15), "[no tags set]"_i18n, "Add simulation tags"_i18n);
tagSimulationButton->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
tagSimulationButton->SetIcon(IconTag);
//currentX+=252;
tagSimulationButton->SetActionCallback({ [this] { c->OpenTags(); } });
AddComponent(tagSimulationButton);
clearSimButton = new ui::Button(ui::Point(Size.X-159, Size.Y-16), ui::Point(17, 15), "", "Erase everything");
clearSimButton = new ui::Button(ui::Point(Size.X-159, Size.Y-16), ui::Point(17, 15), "", "Erase everything"_i18n);
clearSimButton->SetIcon(IconNew);
clearSimButton->Appearance.Margin.Left+=2;
clearSimButton->SetActionCallback({ [this] { c->ClearSim(); } });
AddComponent(clearSimButton);
loginButton = new SplitButton(ui::Point(Size.X-141, Size.Y-16), ui::Point(92, 15), "[sign in]", "Sign into simulation server", "Edit Profile", 19);
loginButton = new SplitButton(ui::Point(Size.X-141, Size.Y-16), ui::Point(92, 15), "[sign in]"_i18n, "Sign into simulation server"_i18n, "Edit Profile"_i18n, 19);
loginButton->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
loginButton->SetIcon(IconLogin);
loginButton->SetSplitActionCallback({
@ -302,30 +301,30 @@ GameView::GameView():
});
AddComponent(loginButton);
simulationOptionButton = new ui::Button(ui::Point(Size.X-48, Size.Y-16), ui::Point(15, 15), "", "Simulation options");
simulationOptionButton = new ui::Button(ui::Point(Size.X-48, Size.Y-16), ui::Point(15, 15), "", "Simulation options"_i18n);
simulationOptionButton->SetIcon(IconSimulationSettings);
simulationOptionButton->Appearance.Margin.Left+=2;
simulationOptionButton->SetActionCallback({ [this] { c->OpenOptions(); } });
AddComponent(simulationOptionButton);
displayModeButton = new ui::Button(ui::Point(Size.X-32, Size.Y-16), ui::Point(15, 15), "", "Renderer options");
displayModeButton = new ui::Button(ui::Point(Size.X-32, Size.Y-16), ui::Point(15, 15), "", "Renderer options"_i18n);
displayModeButton->SetIcon(IconRenderSettings);
displayModeButton->Appearance.Margin.Left+=2;
displayModeButton->SetActionCallback({ [this] { c->OpenRenderOptions(); } });
AddComponent(displayModeButton);
pauseButton = new ui::Button(ui::Point(Size.X-16, Size.Y-16), ui::Point(15, 15), "", "Pause/Resume the simulation"); //Pause
pauseButton = new ui::Button(ui::Point(Size.X-16, Size.Y-16), ui::Point(15, 15), "", "Pause/Resume the simulation"_i18n); //Pause
pauseButton->SetIcon(IconPause);
pauseButton->SetTogglable(true);
pauseButton->SetActionCallback({ [this] { c->SetPaused(pauseButton->GetToggleState()); } });
AddComponent(pauseButton);
ui::Button * tempButton = new ui::Button(ui::Point(WINDOWW-16, WINDOWH-32), ui::Point(15, 15), 0xE065, "Search for elements");
ui::Button * tempButton = new ui::Button(ui::Point(WINDOWW-16, WINDOWH-32), ui::Point(15, 15), 0xE065, "Search for elements"_i18n);
tempButton->Appearance.Margin = ui::Border(0, 2, 3, 2);
tempButton->SetActionCallback({ [this] { c->OpenElementSearch(); } });
AddComponent(tempButton);
colourPicker = new ui::Button(ui::Point((XRES/2)-8, YRES+1), ui::Point(16, 16), "", "Pick Colour");
colourPicker = new ui::Button(ui::Point((XRES/2)-8, YRES+1), ui::Point(16, 16), "", "Pick Colour"_i18n);
colourPicker->SetActionCallback({ [this] { c->OpenColourPicker(); } });
}
@ -416,7 +415,7 @@ void GameView::NotifyMenuListChanged(GameModel * sender)
tempString += menuList[i]->GetIcon();
String description = menuList[i]->GetDescription();
if (i == SC_FAVORITES && !Favorite::Ref().AnyFavorites())
description += " (Use ctrl+shift+click to toggle the favorite status of an element)";
description += " (Use ctrl+shift+click to toggle the favorite status of an element)"_i18n;
auto *tempButton = new MenuButton(ui::Point(WINDOWW-16, currentY), ui::Point(15, 15), tempString, description);
tempButton->Appearance.Margin = ui::Border(0, 2, 3, 2);
tempButton->menuID = i;
@ -685,7 +684,7 @@ void GameView::NotifyColourPresetsChanged(GameModel * sender)
int i = 0;
for(std::vector<ui::Colour>::iterator iter = colours.begin(), end = colours.end(); iter != end; ++iter)
{
ToolButton * tempButton = new ToolButton(ui::Point(currentX, YRES+1), ui::Point(30, 18), "", "", "Decoration Presets.");
ToolButton * tempButton = new ToolButton(ui::Point(currentX, YRES+1), ui::Point(30, 18), "", "", "Decoration Presets."_i18n);
tempButton->Appearance.BackgroundInactive = *iter;
tempButton->SetActionCallback({ [this, i, tempButton] {
c->SetActiveColourPreset(i);
@ -738,15 +737,15 @@ void GameView::NotifyUserChanged(GameModel * sender)
{
if(!sender->GetUser().UserID)
{
loginButton->SetText("[sign in]");
loginButton->SetText("[sign in]"_i18n);
loginButton->SetShowSplit(false);
loginButton->SetRightToolTip("Sign in to simulation server");
loginButton->SetRightToolTip("Sign in to simulation server"_i18n);
}
else
{
loginButton->SetText(sender->GetUser().Username.FromUtf8());
loginButton->SetShowSplit(true);
loginButton->SetRightToolTip("Edit profile");
loginButton->SetRightToolTip("Edit profile"_i18n);
}
// saveSimulationButtonEnabled = sender->GetUser().ID;
saveSimulationButtonEnabled = true;
@ -824,12 +823,12 @@ void GameView::NotifySaveChanged(GameModel * sender)
}
else
{
tagSimulationButton->SetText("[no tags set]");
tagSimulationButton->SetText("[no tags set]"_i18n);
}
}
else
{
tagSimulationButton->SetText("[no tags set]");
tagSimulationButton->SetText("[no tags set]"_i18n);
}
currentSaveType = 1;
int saveID = sender->GetSave()->GetID();
@ -851,13 +850,13 @@ void GameView::NotifySaveChanged(GameModel * sender)
downVoteButton->Appearance.BackgroundDisabled = (ui::Colour(0, 0, 0));
downVoteButton->Appearance.BorderDisabled = ui::Colour(100, 100, 100);
tagSimulationButton->Enabled = false;
tagSimulationButton->SetText("[no tags set]");
tagSimulationButton->SetText("[no tags set]"_i18n);
currentSaveType = 2;
}
else
{
saveSimulationButton->SetShowSplit(false);
saveSimulationButton->SetText("[untitled simulation]");
saveSimulationButton->SetText("[untitled simulation]"_i18n);
reloadButton->Enabled = false;
upVoteButton->Enabled = false;
upVoteButton->Appearance.BackgroundDisabled = (ui::Colour(0, 0, 0));
@ -866,7 +865,7 @@ void GameView::NotifySaveChanged(GameModel * sender)
downVoteButton->Appearance.BackgroundDisabled = (ui::Colour(0, 0, 0));
downVoteButton->Appearance.BorderDisabled = ui::Colour(100, 100, 100),
tagSimulationButton->Enabled = false;
tagSimulationButton->SetText("[no tags set]");
tagSimulationButton->SetText("[no tags set]"_i18n);
currentSaveType = 0;
}
saveSimulationButton->Enabled = (saveSimulationButtonEnabled && saveReuploadAllowed) || ctrlBehaviour;
@ -893,7 +892,7 @@ int GameView::Record(bool record)
else if (!recording)
{
// block so that the return value is correct
bool record = ConfirmPrompt::Blocking("Recording", "You're about to start recording all drawn frames. This will use a load of disk space.");
bool record = ConfirmPrompt::Blocking("Recording"_i18n, "You're about to start recording all drawn frames. This will use a load of disk space."_i18n);
if (record)
{
time_t startTime = time(NULL);
@ -1207,7 +1206,7 @@ void GameView::BeginStampSelection()
selectMode = SelectStamp;
selectPoint1 = selectPoint2 = ui::Point(-1, -1);
isMouseDown = false;
buttonTip = "\x0F\xEF\xEF\020Click-and-drag to specify an area to create a stamp (right click = cancel)";
buttonTip = "\x0F\xEF\xEF\020Click-and-drag to specify an area to create a stamp (right click = cancel)"_i18n;
buttonTipShow = 120;
}
@ -1312,7 +1311,7 @@ void GameView::OnKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl,
|| Client::Ref().GetAuthUser().UserElevation == User::ElevationAdmin) && ctrl)
{
ByteString authorString = Client::Ref().GetAuthorInfo().toStyledString();
new InformationMessage("Save authorship info", authorString.FromUtf8(), true);
new InformationMessage("Save authorship info"_i18n, authorString.FromUtf8(), true);
}
break;
case SDL_SCANCODE_R:
@ -1404,7 +1403,7 @@ void GameView::OnKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl,
selectMode = SelectCopy;
selectPoint1 = selectPoint2 = ui::Point(-1, -1);
isMouseDown = false;
buttonTip = "\x0F\xEF\xEF\020Click-and-drag to specify an area to copy (right click = cancel)";
buttonTip = "\x0F\xEF\xEF\020Click-and-drag to specify an area to copy (right click = cancel)"_i18n;
buttonTipShow = 120;
}
break;
@ -1414,7 +1413,7 @@ void GameView::OnKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl,
selectMode = SelectCut;
selectPoint1 = selectPoint2 = ui::Point(-1, -1);
isMouseDown = false;
buttonTip = "\x0F\xEF\xEF\020Click-and-drag to specify an area to copy then cut (right click = cancel)";
buttonTip = "\x0F\xEF\xEF\020Click-and-drag to specify an area to copy then cut (right click = cancel)"_i18n;
buttonTipShow = 120;
}
break;
@ -1528,7 +1527,7 @@ void GameView::OnFileDrop(ByteString filename)
{
if (!(filename.EndsWith(".cps") || filename.EndsWith(".stm")))
{
new ErrorMessage("Error loading save", "Dropped file is not a TPT save file (.cps or .stm format)");
new ErrorMessage("Error loading save"_i18n, "Dropped file is not a TPT save file (.cps or .stm format)"_i18n);
return;
}
@ -1537,7 +1536,7 @@ void GameView::OnFileDrop(ByteString filename)
return;
if (saveFile->GetError().length())
{
new ErrorMessage("Error loading save", "Dropped save file could not be loaded: " + saveFile->GetError());
new ErrorMessage("Error loading save"_i18n, "Dropped save file could not be loaded: "_i18n + saveFile->GetError());
return;
}
c->LoadSaveFile(saveFile);
@ -1588,13 +1587,16 @@ void GameView::OnTick(float dt)
switch (si.second)
{
case sign::Type::Save:
tooltip << "Go to save ID:" << str.Substr(3, si.first - 3);
tooltip << "Go to save ID:"_i18n << str.Substr(3, si.first - 3);
break;
case sign::Type::Thread:
tooltip << "Open forum thread " << str.Substr(3, si.first - 3) << " in browser";
break;
{
auto openThread = i18nMulti("Open forum thread ", " in browser");
tooltip << openThread[0] << str.Substr(3, si.first - 3) << openThread[1];
break;
}
case sign::Type::Search:
tooltip << "Search for " << str.Substr(3, si.first - 3);
tooltip << "Search for "_i18n << str.Substr(3, si.first - 3);
break;
default: break;
}
@ -1855,7 +1857,7 @@ void GameView::enableCtrlBehaviour()
searchButton->Appearance.BackgroundInactive = searchButton->Appearance.BackgroundHover = ui::Colour(255, 255, 255);
searchButton->Appearance.TextInactive = searchButton->Appearance.TextHover = ui::Colour(0, 0, 0);
searchButton->SetToolTip("Open a simulation from your hard drive.");
searchButton->SetToolTip("Open a simulation from your hard drive."_i18n);
if (currentSaveType == 2)
saveSimulationButton->SetShowSplit(true);
}
@ -1879,7 +1881,7 @@ void GameView::disableCtrlBehaviour()
searchButton->Appearance.BackgroundInactive = ui::Colour(0, 0, 0);
searchButton->Appearance.BackgroundHover = ui::Colour(20, 20, 20);
searchButton->Appearance.TextInactive = searchButton->Appearance.TextHover = ui::Colour(255, 255, 255);
searchButton->SetToolTip("Find & open a simulation. Hold Ctrl to load offline saves.");
searchButton->SetToolTip("Find & open a simulation. Hold Ctrl to load offline saves."_i18n);
if (currentSaveType == 2)
saveSimulationButton->SetShowSplit(false);
}
@ -1915,13 +1917,13 @@ void GameView::UpdateToolStrength()
void GameView::SetSaveButtonTooltips()
{
if (!Client::Ref().GetAuthUser().UserID)
saveSimulationButton->SetToolTips("Overwrite the open simulation on your hard drive.", "Save the simulation to your hard drive. Login to save online.");
saveSimulationButton->SetToolTips("Overwrite the open simulation on your hard drive."_i18n, "Save the simulation to your hard drive. Login to save online."_i18n);
else if (ctrlBehaviour)
saveSimulationButton->SetToolTips("Overwrite the open simulation on your hard drive.", "Save the simulation to your hard drive.");
saveSimulationButton->SetToolTips("Overwrite the open simulation on your hard drive."_i18n, "Save the simulation to your hard drive."_i18n);
else if (saveSimulationButton->GetShowSplit())
saveSimulationButton->SetToolTips("Re-upload the current simulation", "Modify simulation properties");
saveSimulationButton->SetToolTips("Re-upload the current simulation"_i18n, "Modify simulation properties"_i18n);
else
saveSimulationButton->SetToolTips("Re-upload the current simulation", "Upload a new simulation. Hold Ctrl to save offline.");
saveSimulationButton->SetToolTips("Re-upload the current simulation"_i18n, "Upload a new simulation. Hold Ctrl to save offline."_i18n);
}
void GameView::OnDraw()
@ -2096,7 +2098,8 @@ void GameView::OnDraw()
if (recording)
{
String sampleInfo = String::Build("#", screenshotIndex, " ", String(0xE00E), " REC");
auto rec = i18nMulti("#", " ", " REC");
String sampleInfo = String::Build(rec[0], screenshotIndex, rec[1], String(0xE00E), rec[2]);
int textWidth = Graphics::textwidth(sampleInfo);
g->fillrect(XRES-20-textWidth, 12, textWidth+8, 15, 0, 0, 0, 255*0.5);
@ -2125,17 +2128,17 @@ void GameView::OnDraw()
{
if (type == PT_LAVA && c->IsValidElement(ctype))
{
sampleInfo << "Molten " << c->ElementResolve(ctype, -1);
sampleInfo << "Molten "_i18n << c->ElementResolve(ctype, -1);
}
else if ((type == PT_PIPE || type == PT_PPIP) && c->IsValidElement(ctype))
{
if (ctype == PT_LAVA && c->IsValidElement((int)sample.particle.pavg[1]))
{
sampleInfo << c->ElementResolve(type, -1) << " with molten " << c->ElementResolve((int)sample.particle.pavg[1], -1);
sampleInfo << c->ElementResolve(type, -1) << " with molten "_i18n << c->ElementResolve((int)sample.particle.pavg[1], -1);
}
else
{
sampleInfo << c->ElementResolve(type, -1) << " with " << c->ElementResolve(ctype, (int)sample.particle.pavg[1]);
sampleInfo << c->ElementResolve(type, -1) << " with "_i18n << c->ElementResolve(ctype, (int)sample.particle.pavg[1]);
}
}
else if (type == PT_LIFE)
@ -2145,11 +2148,11 @@ void GameView::OnDraw()
else if (type == PT_FILT)
{
sampleInfo << c->ElementResolve(type, ctype);
String filtModes[] = {"set colour", "AND", "OR", "subtract colour", "red shift", "blue shift", "no effect", "XOR", "NOT", "old QRTZ scattering", "variable red shift", "variable blue shift"};
auto filtModes = i18nMulti("set colour", "AND", "OR", "subtract colour", "red shift", "blue shift", "no effect", "XOR", "NOT", "old QRTZ scattering", "variable red shift", "variable blue shift");
if (sample.particle.tmp>=0 && sample.particle.tmp<=11)
sampleInfo << " (" << filtModes[sample.particle.tmp] << ")";
else
sampleInfo << " (unknown mode)";
sampleInfo << " (unknown mode)"_i18n;
}
else
{
@ -2164,8 +2167,8 @@ void GameView::OnDraw()
else
sampleInfo << " ()";
}
sampleInfo << ", Temp: " << (sample.particle.temp - 273.15f) << " C";
sampleInfo << ", Life: " << sample.particle.life;
sampleInfo << ", Temp: "_i18n << (sample.particle.temp - 273.15f) << " C"_i18n;
sampleInfo << ", Life: "_i18n << sample.particle.life;
if (sample.particle.type != PT_RFRG && sample.particle.type != PT_RFGL)
{
if (sample.particle.type == PT_CONV)
@ -2174,39 +2177,39 @@ void GameView::OnDraw()
TYP(sample.particle.tmp),
ID(sample.particle.tmp));
if (elemName == "")
sampleInfo << ", Tmp: " << sample.particle.tmp;
sampleInfo << ", Tmp: "_i18n << sample.particle.tmp;
else
sampleInfo << ", Tmp: " << elemName;
sampleInfo << ", Tmp: "_i18n << elemName;
}
else
sampleInfo << ", Tmp: " << sample.particle.tmp;
sampleInfo << ", Tmp: "_i18n << sample.particle.tmp;
}
// only elements that use .tmp2 show it in the debug HUD
if (type == PT_CRAY || type == PT_DRAY || type == PT_EXOT || type == PT_LIGH || type == PT_SOAP || type == PT_TRON || type == PT_VIBR || type == PT_VIRS || type == PT_WARP || type == PT_LCRY || type == PT_CBNW || type == PT_TSNS || type == PT_DTEC || type == PT_LSNS || type == PT_PSTN || type == PT_LDTC)
sampleInfo << ", Tmp2: " << sample.particle.tmp2;
sampleInfo << ", Tmp2: "_i18n << sample.particle.tmp2;
sampleInfo << ", Pressure: " << sample.AirPressure;
sampleInfo << ", Pressure: "_i18n << sample.AirPressure;
}
else
{
sampleInfo << c->BasicParticleInfo(sample.particle);
sampleInfo << ", Temp: " << sample.particle.temp - 273.15f << " C";
sampleInfo << ", Pressure: " << sample.AirPressure;
sampleInfo << ", Temp: "_i18n << sample.particle.temp - 273.15f << " C"_i18n;
sampleInfo << ", Pressure: "_i18n << sample.AirPressure;
}
}
else if (sample.WallType)
{
sampleInfo << c->WallName(sample.WallType);
sampleInfo << ", Pressure: " << sample.AirPressure;
sampleInfo << ", Pressure: "_i18n << sample.AirPressure;
}
else if (sample.isMouseInSim)
{
sampleInfo << "Empty, Pressure: " << sample.AirPressure;
sampleInfo << "Empty, Pressure: "_i18n << sample.AirPressure;
}
else
{
sampleInfo << "Empty";
sampleInfo << "Empty"_i18n;
}
int textWidth = Graphics::textwidth(sampleInfo.Build());
@ -2264,7 +2267,7 @@ void GameView::OnDraw()
sampleInfo << ", GX: " << sample.GravityVelocityX << " GY: " << sample.GravityVelocityY;
if (c->GetAHeatEnable())
sampleInfo << ", AHeat: " << sample.AirTemperature - 273.15f << " C";
sampleInfo << ", AHeat: "_i18n << sample.AirTemperature - 273.15f << " C"_i18n;
textWidth = Graphics::textwidth(sampleInfo.Build());
g->fillrect(XRES-20-textWidth, 27, textWidth+8, 14, 0, 0, 0, alpha*0.5f);
@ -2276,23 +2279,26 @@ void GameView::OnDraw()
{
//FPS and some version info
StringBuilder fpsInfo;
fpsInfo << Format::Precision(2) << "FPS: " << ui::Engine::Ref().GetFps();
fpsInfo << Format::Precision(2) << "FPS: "_i18n << ui::Engine::Ref().GetFps();
if (showDebug)
{
if (ren->findingElement)
fpsInfo << " Parts: " << ren->foundElements << "/" << sample.NumParts;
fpsInfo << " Parts: "_i18n << ren->foundElements << "/" << sample.NumParts;
else
fpsInfo << " Parts: " << sample.NumParts;
fpsInfo << " Parts: "_i18n << sample.NumParts;
}
if (c->GetReplaceModeFlags()&REPLACE_MODE)
fpsInfo << " [REPLACE MODE]";
fpsInfo << " [REPLACE MODE]"_i18n;
if (c->GetReplaceModeFlags()&SPECIFIC_DELETE)
fpsInfo << " [SPECIFIC DELETE]";
fpsInfo << " [SPECIFIC DELETE]"_i18n;
if (ren && ren->GetGridSize())
fpsInfo << " [GRID: " << ren->GetGridSize() << "]";
{
auto grid = i18nMulti("[GRID: ", "]");
fpsInfo << grid[0] << ren->GetGridSize() << grid[1];
}
if (ren && ren->findingElement)
fpsInfo << " [FIND]";
fpsInfo << " [FIND]"_i18n;
int textWidth = Graphics::textwidth(fpsInfo.Build());
int alpha = 255-introText*5;

View File

@ -41,13 +41,13 @@ sim(sim_)
{
properties = Particle::GetProperties();
ui::Label * messageLabel = new ui::Label(ui::Point(4, 5), ui::Point(Size.X-8, 14), "Edit property");
ui::Label * messageLabel = new ui::Label(ui::Point(4, 5), ui::Point(Size.X-8, 14), "Edit property"_i18n);
messageLabel->SetTextColour(style::Colour::InformationTitle);
messageLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
messageLabel->Appearance.VerticalAlign = ui::Appearance::AlignTop;
AddComponent(messageLabel);
ui::Button * okayButton = new ui::Button(ui::Point(0, Size.Y-17), ui::Point(Size.X, 17), "OK");
ui::Button * okayButton = new ui::Button(ui::Point(0, Size.Y-17), ui::Point(Size.X, 17), "OK"_i18n);
okayButton->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
okayButton->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
okayButton->Appearance.BorderInactive = ui::Colour(200, 200, 200);
@ -69,7 +69,7 @@ sim(sim_)
}
property->SetOption(Client::Ref().GetPrefInteger("Prop.Type", 0));
textField = new ui::Textbox(ui::Point(8, 46), ui::Point(Size.X-16, 16), "", "[value]");
textField = new ui::Textbox(ui::Point(8, 46), ui::Point(Size.X-16, 16), "", "[value]"_i18n);
textField->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
textField->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
textField->SetText(Client::Ref().GetPrefString("Prop.Value", ""));
@ -120,7 +120,7 @@ void PropertyWindow::SetProperty()
if (properties[property->GetOption().second].Name == "type" && (v < 0 || v >= PT_NUM || !sim->elements[v].Enabled))
{
new ErrorMessage("Could not set property", "Invalid particle type");
new ErrorMessage("Could not set property"_i18n, "Invalid particle type"_i18n);
return;
}
@ -176,14 +176,14 @@ void PropertyWindow::SetProperty()
}
break;
default:
new ErrorMessage("Could not set property", "Invalid property");
new ErrorMessage("Could not set property"_i18n, "Invalid property"_i18n);
return;
}
tool->propOffset = properties[property->GetOption().second].Offset;
tool->propType = properties[property->GetOption().second].Type;
tool->changeType = properties[property->GetOption().second].Name == "type";
} catch (const std::exception& ex) {
new ErrorMessage("Could not set property", "Invalid value provided");
new ErrorMessage("Could not set property"_i18n, "Invalid value provided"_i18n);
return;
}
Client::Ref().SetPref("Prop.Type", property->GetOption().second);

View File

@ -6,7 +6,7 @@
#include "simulation/Simulation.h"
SandEffectOption::SandEffectOption(GameModel * m):
QuickOption("P", "Sand effect", m, Toggle)
QuickOption("P", "Sand effect"_i18n, m, Toggle)
{
}
@ -22,7 +22,7 @@ void SandEffectOption::perform()
DrawGravOption::DrawGravOption(GameModel * m):
QuickOption("G", "Draw gravity field \bg(ctrl+g)", m, Toggle)
QuickOption("G", "Draw gravity field \bg(ctrl+g)"_i18n, m, Toggle)
{
}
@ -38,7 +38,7 @@ void DrawGravOption::perform()
DecorationsOption::DecorationsOption(GameModel * m):
QuickOption("D", "Draw decorations \bg(ctrl+b)", m, Toggle)
QuickOption("D", "Draw decorations \bg(ctrl+b)"_i18n, m, Toggle)
{
}
@ -54,7 +54,7 @@ void DecorationsOption::perform()
NGravityOption::NGravityOption(GameModel * m):
QuickOption("N", "Newtonian Gravity \bg(n)", m, Toggle)
QuickOption("N", "Newtonian Gravity \bg(n)"_i18n, m, Toggle)
{
}
@ -70,7 +70,7 @@ void NGravityOption::perform()
AHeatOption::AHeatOption(GameModel * m):
QuickOption("A", "Ambient heat \bg(u)", m, Toggle)
QuickOption("A", "Ambient heat \bg(u)"_i18n, m, Toggle)
{
}
@ -86,7 +86,7 @@ void AHeatOption::perform()
ConsoleShowOption::ConsoleShowOption(GameModel * m, GameController * c_):
QuickOption("C", "Show Console \bg(~)", m, Toggle)
QuickOption("C", "Show Console \bg(~)"_i18n, m, Toggle)
{
c = c_;
}

View File

@ -61,13 +61,13 @@ SignWindow::SignWindow(SignTool * tool_, Simulation * sim_, int signID_, ui::Poi
signID(signID_),
signPosition(position_)
{
ui::Label * messageLabel = new ui::Label(ui::Point(4, 5), ui::Point(Size.X-8, 15), "New sign");
ui::Label * messageLabel = new ui::Label(ui::Point(4, 5), ui::Point(Size.X-8, 15), "New sign"_i18n);
messageLabel->SetTextColour(style::Colour::InformationTitle);
messageLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
messageLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
AddComponent(messageLabel);
ui::Button * okayButton = new ui::Button(ui::Point(0, Size.Y-16), ui::Point(Size.X, 16), "OK");
ui::Button * okayButton = new ui::Button(ui::Point(0, Size.Y-16), ui::Point(Size.X, 16), "OK"_i18n);
okayButton->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
okayButton->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
okayButton->Appearance.BorderInactive = (ui::Colour(200, 200, 200));
@ -86,21 +86,21 @@ SignWindow::SignWindow(SignTool * tool_, Simulation * sim_, int signID_, ui::Poi
AddComponent(okayButton);
SetOkayButton(okayButton);
ui::Label * tempLabel = new ui::Label(ui::Point(8, 48), ui::Point(40, 15), "Pointer:");
ui::Label * tempLabel = new ui::Label(ui::Point(8, 48), ui::Point(40, 15), "Pointer:"_i18n);
okayButton->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
okayButton->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
AddComponent(tempLabel);
justification = new ui::DropDown(ui::Point(52, 48), ui::Point(55, 16));
AddComponent(justification);
justification->AddOption(std::pair<String, int>(0xE020 + String(" Left"), (int)sign::Left));
justification->AddOption(std::pair<String, int>(0xE01E + String(" Middle"), (int)sign::Middle));
justification->AddOption(std::pair<String, int>(0xE01F + String(" Right"), (int)sign::Right));
justification->AddOption(std::pair<String, int>(0xE01D + String(" None"), (int)sign::None));
justification->AddOption(std::pair<String, int>(0xE020 + " Left"_i18n, (int)sign::Left));
justification->AddOption(std::pair<String, int>(0xE01E + " Middle"_i18n, (int)sign::Middle));
justification->AddOption(std::pair<String, int>(0xE01F + " Right"_i18n, (int)sign::Right));
justification->AddOption(std::pair<String, int>(0xE01D + " None"_i18n, (int)sign::None));
justification->SetOption(1);
justification->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
textField = new ui::Textbox(ui::Point(8, 25), ui::Point(Size.X-16, 17), "", "[message]");
textField = new ui::Textbox(ui::Point(8, 25), ui::Point(Size.X-16, 17), "", "[message]"_i18n);
textField->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
textField->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
textField->SetLimit(45);
@ -116,13 +116,13 @@ SignWindow::SignWindow(SignTool * tool_, Simulation * sim_, int signID_, ui::Poi
if(signID!=-1)
{
messageLabel->SetText("Edit sign");
messageLabel->SetText("Edit sign"_i18n);
textField->SetText(sim->signs[signID].text);
justification->SetOption(sim->signs[signID].ju);
ui::Point position = ui::Point(justification->Position.X+justification->Size.X+3, 48);
ui::Button * moveButton = new ui::Button(position, ui::Point(((Size.X-position.X-8)/2)-2, 16), "Move");
ui::Button * moveButton = new ui::Button(position, ui::Point(((Size.X-position.X-8)/2)-2, 16), "Move"_i18n);
moveButton->SetActionCallback({ [this] {
if (signID!=-1)
{
@ -134,7 +134,7 @@ SignWindow::SignWindow(SignTool * tool_, Simulation * sim_, int signID_, ui::Poi
AddComponent(moveButton);
position = ui::Point(justification->Position.X+justification->Size.X+3, 48)+ui::Point(moveButton->Size.X+3, 0);
ui::Button * deleteButton = new ui::Button(position, ui::Point((Size.X-position.X-8)-1, 16), "Delete");
ui::Button * deleteButton = new ui::Button(position, ui::Point((Size.X-position.X-8)-1, 16), "Delete"_i18n);
//deleteButton->SetIcon(IconDelete);
deleteButton->SetActionCallback({ [this] {
CloseActiveWindow();

View File

@ -47,7 +47,7 @@ class SignTool: public Tool
public:
GameModel * gameModel;
SignTool(GameModel *model):
Tool(0, "SIGN", "Sign. Displays text. Click on a sign to edit it or anywhere else to place a new one.", 0, 0, 0, "DEFAULT_UI_SIGN", SignTool::GetIcon),
Tool(0, "SIGN", "Sign. Displays text. Click on a sign to edit it or anywhere else to place a new one."_i18n, 0, 0, 0, "DEFAULT_UI_SIGN", SignTool::GetIcon),
gameModel(model)
{
}
@ -65,7 +65,7 @@ class SampleTool: public Tool
GameModel * gameModel;
public:
SampleTool(GameModel *model):
Tool(0, "SMPL", "Sample an element on the screen.", 0, 0, 0, "DEFAULT_UI_SAMPLE", SampleTool::GetIcon),
Tool(0, "SMPL", "Sample an element on the screen."_i18n, 0, 0, 0, "DEFAULT_UI_SAMPLE", SampleTool::GetIcon),
gameModel(model)
{
}
@ -82,7 +82,7 @@ class PropertyTool: public Tool
{
public:
PropertyTool():
Tool(0, "PROP", "Property Drawing Tool. Use to alter the properties of elements in the field.", 0xfe, 0xa9, 0x00, "DEFAULT_UI_PROPERTY", NULL)
Tool(0, "PROP", "Property Drawing Tool. Use to alter the properties of elements in the field."_i18n, 0xfe, 0xa9, 0x00, "DEFAULT_UI_PROPERTY", NULL)
{
}
StructProperty::PropertyType propType;

View File

@ -25,7 +25,7 @@ namespace ui
ui::Button::OnMouseClick(x, y, button);
ClipboardPush(ButtonText.ToUtf8());
copyTextLabel->SetText("Copied!");
copyTextLabel->SetText("Copied!"_i18n);
Appearance.TextInactive = ui::Colour(180, 230, 180);
Appearance.TextHover = ui::Colour(180, 230, 180);

View File

@ -77,7 +77,7 @@ void Engine::Exit()
void Engine::ConfirmExit()
{
new ConfirmPrompt("You are about to quit", "Are you sure you want to exit the game?", { [] {
new ConfirmPrompt("You are about to quit"_i18n, "Are you sure you want to exit the game?"_i18n, { [] {
ui::Engine::Ref().Exit();
} });
}

View File

@ -23,7 +23,7 @@ Label::Label(Point position, Point size, String labelText):
SetText(labelText);
menu = new ContextMenu(this);
menu->AddItem(ContextMenuItem("Copy", 0, true));
menu->AddItem(ContextMenuItem("Copy"_i18n, 0, true));
}
Label::~Label()

View File

@ -18,7 +18,7 @@ using namespace ui;
struct RichTextParseException: public std::exception {
ByteString message;
public:
RichTextParseException(String message = String("Parse error")): message(message.ToUtf8()) {}
RichTextParseException(String message = String("Parse error"_i18n)): message(message.ToUtf8()) {}
const char * what() const throw() override
{
return message.c_str();
@ -77,7 +77,7 @@ void RichLabel::updateRichText()
if(current == '{')
{
if(stackPos > 255)
throw RichTextParseException("Too many nested regions");
throw RichTextParseException("Too many nested regions"_i18n);
stackPos++;
regionsStack[stackPos].start = finalTextPos;
regionsStack[stackPos].finish = finalTextPos;
@ -94,7 +94,7 @@ void RichLabel::updateRichText()
}
else
{
throw RichTextParseException("Unexpected '}'");
throw RichTextParseException("Unexpected '}'"_i18n);
}
}
else
@ -123,7 +123,7 @@ void RichLabel::updateRichText()
{
if(current != ':')
{
throw RichTextParseException("Expected ':'");
throw RichTextParseException("Expected ':'"_i18n);
}
state = ReadData;
currentDataPos = 0;
@ -145,14 +145,15 @@ void RichLabel::updateRichText()
}
if(stackPos != -1)
throw RichTextParseException("Unclosed region");
throw RichTextParseException("Unclosed region"_i18n);
finalText[finalTextPos] = 0;
displayText = String(finalText);
}
catch (const RichTextParseException & e)
{
displayText = "\br[Parse exception: " + ByteString(e.what()).FromUtf8() + "]";
auto errMsg = i18nMulti("\br[Parse exception: ", "]");
displayText = errMsg[0] + ByteString(e.what()).FromUtf8() + errMsg[1];
regions.clear();
}
delete[] currentData;

View File

@ -194,7 +194,7 @@ void SaveButton::Draw(const Point& screenPos)
g->draw_image(thumbnail.get(), screenPos.X+(Size.X-thumbSize.X)/2, screenPos.Y+(Size.Y-21-thumbSize.Y)/2, 255);
}
else if (file && !file->GetGameSave())
g->drawtext(screenPos.X+(Size.X-Graphics::textwidth("Error loading save"))/2, screenPos.Y+(Size.Y-28)/2, "Error loading save", 180, 180, 180, 255);
g->drawtext(screenPos.X+(Size.X-Graphics::textwidth("Error loading save"_i18n))/2, screenPos.Y+(Size.Y-28)/2, "Error loading save"_i18n, 180, 180, 180, 255);
if(save)
{
if(save->id)
@ -317,18 +317,18 @@ void SaveButton::AddContextMenu(int menuType)
if (menuType == 0) //Save browser
{
menu = new ContextMenu(this);
menu->AddItem(ContextMenuItem("Open", 0, true));
menu->AddItem(ContextMenuItem("Open"_i18n, 0, true));
if (Client::Ref().GetAuthUser().UserID)
menu->AddItem(ContextMenuItem("Select", 1, true));
menu->AddItem(ContextMenuItem("View History", 2, true));
menu->AddItem(ContextMenuItem("More by this user", 3, true));
menu->AddItem(ContextMenuItem("Select"_i18n, 1, true));
menu->AddItem(ContextMenuItem("View History"_i18n, 2, true));
menu->AddItem(ContextMenuItem("More by this user"_i18n, 3, true));
}
else if (menuType == 1) //Local save browser
{
menu = new ContextMenu(this);
menu->AddItem(ContextMenuItem("Open", 0, true));
menu->AddItem(ContextMenuItem("Rename", 2, true));
menu->AddItem(ContextMenuItem("Delete", 3, true));
menu->AddItem(ContextMenuItem("Open"_i18n, 0, true));
menu->AddItem(ContextMenuItem("Rename"_i18n, 2, true));
menu->AddItem(ContextMenuItem("Delete"_i18n, 3, true));
}
}
@ -419,9 +419,9 @@ void SaveButton::DoSelection()
if(menu)
{
if(selected)
menu->SetItem(1, "Deselect");
menu->SetItem(1, "Deselect"_i18n);
else
menu->SetItem(1, "Select");
menu->SetItem(1, "Select"_i18n);
}
if (selectable && actionCallback.selected)
actionCallback.selected();

View File

@ -32,9 +32,9 @@ Textbox::Textbox(Point position, Point size, String textboxText, String textboxP
cursor = text.length();
menu->RemoveItem(0);
menu->AddItem(ContextMenuItem("Cut", 1, true));
menu->AddItem(ContextMenuItem("Copy", 0, true));
menu->AddItem(ContextMenuItem("Paste", 2, true));
menu->AddItem(ContextMenuItem("Cut"_i18n, 1, true));
menu->AddItem(ContextMenuItem("Copy"_i18n, 0, true));
menu->AddItem(ContextMenuItem("Paste"_i18n, 2, true));
}
void Textbox::SetHidden(bool hidden)
@ -42,9 +42,9 @@ void Textbox::SetHidden(bool hidden)
menu->RemoveItem(0);
menu->RemoveItem(1);
menu->RemoveItem(2);
menu->AddItem(ContextMenuItem("Cut", 1, !hidden));
menu->AddItem(ContextMenuItem("Copy", 0, !hidden));
menu->AddItem(ContextMenuItem("Paste", 2, true));
menu->AddItem(ContextMenuItem("Cut"_i18n, 1, !hidden));
menu->AddItem(ContextMenuItem("Copy"_i18n, 0, !hidden));
menu->AddItem(ContextMenuItem("Paste"_i18n, 2, true));
masked = hidden;
}

View File

@ -37,12 +37,9 @@ SaveFile * LocalBrowserController::GetSave()
void LocalBrowserController::RemoveSelected()
{
StringBuilder desc;
desc << "Are you sure you want to delete " << browserModel->GetSelected().size() << " stamp";
if(browserModel->GetSelected().size()>1)
desc << "s";
desc << "?";
new ConfirmPrompt("Delete stamps", desc.Build(), { [this] { removeSelectedC(); } });
auto deleteConfirm = i18nMulti("Are you sure you want to delete ", "?");
size_t count = browserModel->GetSelected().size();
new ConfirmPrompt("Delete stamps"_i18n, String::Build(deleteConfirm[0], count, ' ', i18nPlural("stamp", count), deleteConfirm[1]), { [this] { removeSelectedC(); } });
}
void LocalBrowserController::removeSelectedC()
@ -57,7 +54,8 @@ void LocalBrowserController::removeSelectedC()
{
for (size_t i = 0; i < saves.size(); i++)
{
notifyStatus(String::Build("Deleting stamp [", saves[i].FromUtf8(), "] ..."));
auto deleting = i18nMulti("Deleting stamp [", "] ...");
notifyStatus(String::Build(deleting[0], saves[i].FromUtf8(), deleting[1]));
Client::Ref().DeleteStamp(saves[i]);
notifyProgress((float(i+1)/float(saves.size())*100));
}
@ -71,12 +69,12 @@ void LocalBrowserController::removeSelectedC()
};
std::vector<ByteString> selected = browserModel->GetSelected();
new TaskWindow("Removing stamps", new RemoveSavesTask(this, selected));
new TaskWindow("Removing stamps"_i18n, new RemoveSavesTask(this, selected));
}
void LocalBrowserController::RescanStamps()
{
new ConfirmPrompt("Rescan", "Rescanning the stamps folder can find stamps added to the stamps folder or recover stamps when the stamps.def file has been lost or damaged. However, be warned that this will mess up the current sorting order", { [this] { rescanStampsC(); } });
new ConfirmPrompt("Rescan"_i18n, "Rescanning the stamps folder can find stamps added to the stamps folder or recover stamps when the stamps.def file has been lost or damaged. However, be warned that this will mess up the current sorting order"_i18n, { [this] { rescanStampsC(); } });
}
void LocalBrowserController::rescanStampsC()

View File

@ -22,9 +22,9 @@ LocalBrowserView::LocalBrowserView():
lastChanged(0),
pageCount(0)
{
nextButton = new ui::Button(ui::Point(WINDOWW-52, WINDOWH-18), ui::Point(50, 16), String("Next ") + 0xE015);
previousButton = new ui::Button(ui::Point(2, WINDOWH-18), ui::Point(50, 16), 0xE016 + String(" Prev"));
undeleteButton = new ui::Button(ui::Point(WINDOWW-122, WINDOWH-18), ui::Point(60, 16), "Rescan");
nextButton = new ui::Button(ui::Point(WINDOWW-52, WINDOWH-18), ui::Point(50, 16), "Next "_i18n + 0xE015);
previousButton = new ui::Button(ui::Point(2, WINDOWH-18), ui::Point(50, 16), 0xE016 + " Prev"_i18n);
undeleteButton = new ui::Button(ui::Point(WINDOWW-122, WINDOWH-18), ui::Point(60, 16), "Rescan"_i18n);
AddComponent(nextButton);
AddComponent(previousButton);
AddComponent(undeleteButton);
@ -32,7 +32,8 @@ LocalBrowserView::LocalBrowserView():
pageTextbox = new ui::Textbox(ui::Point(283, WINDOWH-18), ui::Point(41, 16), "");
pageTextbox->SetActionCallback({ [this] { textChanged(); } });
pageTextbox->SetInputType(ui::Textbox::Number);
pageLabel = new ui::Label(ui::Point(0, WINDOWH-18), ui::Point(30, 16), "Page"); //page [TEXTBOX] of y
auto pageOf = i18nMulti("Page", "of "); //page [TEXTBOX] of y
pageLabel = new ui::Label(ui::Point(0, WINDOWH-18), ui::Point(30, 16), pageOf[0]);
pageLabel->Appearance.HorizontalAlign = ui::Appearance::AlignRight;
pageCountLabel = new ui::Label(ui::Point(WINDOWW/2+6, WINDOWH-18), ui::Point(50, 16), "");
pageCountLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
@ -50,7 +51,7 @@ LocalBrowserView::LocalBrowserView():
undeleteButton->SetActionCallback({ [this] { c->RescanStamps(); } });
removeSelected = new ui::Button(ui::Point(((WINDOWW-100)/2), WINDOWH-18), ui::Point(100, 16), "Delete");
removeSelected = new ui::Button(ui::Point(((WINDOWW-100)/2), WINDOWH-18), ui::Point(100, 16), "Delete"_i18n);
removeSelected->Visible = false;
removeSelected->SetActionCallback({ [this] { c->RemoveSelected(); } });
AddComponent(removeSelected);
@ -59,10 +60,8 @@ LocalBrowserView::LocalBrowserView():
void LocalBrowserView::textChanged()
{
int num = pageTextbox->GetText().ToNumber<int>(true);
if (num < 0) //0 is allowed so that you can backspace the 1
pageTextbox->SetText("1");
else if (num > pageCount)
pageTextbox->SetText(String::Build(pageCount));
if(num < 0 || num > pageCount) //0 is allowed so that you can backspace the 1
pageTextbox->SetText(String::Build(num < 0 ? 1 : pageCount));
changed = true;
lastChanged = GetTicks()+600;
}
@ -86,7 +85,8 @@ void LocalBrowserView::NotifyPageChanged(LocalBrowserModel * sender)
}
else
{
String pageInfo = String::Build("of ", pageCount);
auto pageOf = i18nMulti("Page", "of ");
String pageInfo = String::Build(pageOf[1], pageCount);
pageCountLabel->SetText(pageInfo);
int width = Graphics::textwidth(pageInfo);

View File

@ -3,6 +3,7 @@
#include "LoginView.h"
#include "client/Client.h"
#include "Config.h"
LoginModel::LoginModel():
currentUser(0, "")
@ -14,19 +15,19 @@ void LoginModel::Login(ByteString username, ByteString password)
{
if (username.Contains("@"))
{
statusText = "Use your Powder Toy account to log in, not your email. If you don't have a Powder Toy account, you can create one at https://powdertoy.co.uk/Register.html";
statusText = "Use your Powder Toy account to log in, not your email. If you don't have a Powder Toy account, you can create one at "_i18n + ByteString(SCHEME SERVER "/Register.html").FromAscii();
loginStatus = false;
notifyStatusChanged();
return;
}
statusText = "Logging in...";
statusText = "Logging in..."_i18n;
loginStatus = false;
notifyStatusChanged();
LoginStatus status = Client::Ref().Login(username, password, currentUser);
switch(status)
{
case LoginOkay:
statusText = "Logged in";
statusText = "Logged in"_i18n;
loginStatus = true;
break;
case LoginError:

View File

@ -16,12 +16,12 @@
LoginView::LoginView():
ui::Window(ui::Point(-1, -1), ui::Point(200, 87)),
loginButton(new ui::Button(ui::Point(200-100, 87-17), ui::Point(100, 17), "Sign in")),
cancelButton(new ui::Button(ui::Point(0, 87-17), ui::Point(101, 17), "Sign Out")),
titleLabel(new ui::Label(ui::Point(4, 5), ui::Point(200-16, 16), "Server login")),
loginButton(new ui::Button(ui::Point(200-100, 87-17), ui::Point(100, 17), "Sign in"_i18n)),
cancelButton(new ui::Button(ui::Point(0, 87-17), ui::Point(101, 17), "Sign Out"_i18n)),
titleLabel(new ui::Label(ui::Point(4, 5), ui::Point(200-16, 16), "Server login"_i18n)),
infoLabel(new ui::Label(ui::Point(8, 67), ui::Point(200-16, 16), "")),
usernameField(new ui::Textbox(ui::Point(8, 25), ui::Point(200-16, 17), Client::Ref().GetAuthUser().Username.FromUtf8(), "[username]")),
passwordField(new ui::Textbox(ui::Point(8, 46), ui::Point(200-16, 17), "", "[password]")),
usernameField(new ui::Textbox(ui::Point(8, 25), ui::Point(200-16, 17), Client::Ref().GetAuthUser().Username.FromUtf8(), "[username]"_i18n)),
passwordField(new ui::Textbox(ui::Point(8, 46), ui::Point(200-16, 17), "", "[password]"_i18n)),
targetSize(0, 0)
{
targetSize = Size;

View File

@ -28,7 +28,7 @@ OptionsView::OptionsView():
c->Size.X = Size.X - c->Position.X - 12;
};
ui::Label * tempLabel = new ui::Label(ui::Point(4, 1), ui::Point(Size.X-8, 22), "Simulation Options");
ui::Label * tempLabel = new ui::Label(ui::Point(4, 1), ui::Point(Size.X-8, 22), "Simulation Options"_i18n);
tempLabel->SetTextColour(style::Colour::InformationTitle);
tempLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
tempLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
@ -55,48 +55,48 @@ OptionsView::OptionsView():
AddComponent(scrollPanel);
heatSimulation = new ui::Checkbox(ui::Point(8, currentY), ui::Point(1, 16), "Heat simulation \bgIntroduced in version 34", "");
heatSimulation = new ui::Checkbox(ui::Point(8, currentY), ui::Point(1, 16), "Heat simulation \bgIntroduced in version 34"_i18n, "");
autowidth(heatSimulation);
heatSimulation->SetActionCallback({ [this] { c->SetHeatSimulation(heatSimulation->GetChecked()); } });
scrollPanel->AddChild(heatSimulation);
currentY+=14;
tempLabel = new ui::Label(ui::Point(24, currentY), ui::Point(1, 16), "\bgCan cause odd behaviour when disabled");
tempLabel = new ui::Label(ui::Point(24, currentY), ui::Point(1, 16), "\bgCan cause odd behaviour when disabled"_i18n);
autowidth(tempLabel);
tempLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
tempLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
scrollPanel->AddChild(tempLabel);
currentY+=16;
ambientHeatSimulation = new ui::Checkbox(ui::Point(8, currentY), ui::Point(1, 16), "Ambient heat simulation \bgIntroduced in version 50", "");
ambientHeatSimulation = new ui::Checkbox(ui::Point(8, currentY), ui::Point(1, 16), "Ambient heat simulation \bgIntroduced in version 50"_i18n, "");
autowidth(ambientHeatSimulation);
ambientHeatSimulation->SetActionCallback({ [this] { c->SetAmbientHeatSimulation(ambientHeatSimulation->GetChecked()); } });
scrollPanel->AddChild(ambientHeatSimulation);
currentY+=14;
tempLabel = new ui::Label(ui::Point(24, currentY), ui::Point(1, 16), "\bgCan cause odd / broken behaviour with many saves");
tempLabel = new ui::Label(ui::Point(24, currentY), ui::Point(1, 16), "\bgCan cause odd / broken behaviour with many saves"_i18n);
autowidth(tempLabel);
tempLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
tempLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
scrollPanel->AddChild(tempLabel);
currentY+=16;
newtonianGravity = new ui::Checkbox(ui::Point(8, currentY), ui::Point(1, 16), "Newtonian gravity \bgIntroduced in version 48", "");
newtonianGravity = new ui::Checkbox(ui::Point(8, currentY), ui::Point(1, 16), "Newtonian gravity \bgIntroduced in version 48"_i18n, "");
autowidth(newtonianGravity);
newtonianGravity->SetActionCallback({ [this] { c->SetNewtonianGravity(newtonianGravity->GetChecked()); } });
scrollPanel->AddChild(newtonianGravity);
currentY+=14;
tempLabel = new ui::Label(ui::Point(24, currentY), ui::Point(1, 16), "\bgMay cause poor performance on older computers");
tempLabel = new ui::Label(ui::Point(24, currentY), ui::Point(1, 16), "\bgMay cause poor performance on older computers"_i18n);
autowidth(tempLabel);
tempLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
tempLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
scrollPanel->AddChild(tempLabel);
currentY+=16;
waterEqualisation = new ui::Checkbox(ui::Point(8, currentY), ui::Point(1, 16), "Water equalisation \bgIntroduced in version 61", "");
waterEqualisation = new ui::Checkbox(ui::Point(8, currentY), ui::Point(1, 16), "Water equalisation \bgIntroduced in version 61"_i18n, "");
autowidth(waterEqualisation);
waterEqualisation->SetActionCallback({ [this] { c->SetWaterEqualisation(waterEqualisation->GetChecked()); } });
scrollPanel->AddChild(waterEqualisation);
currentY+=14;
tempLabel = new ui::Label(ui::Point(24, currentY), ui::Point(1, 16), "\bgMay cause poor performance with a lot of water");
tempLabel = new ui::Label(ui::Point(24, currentY), ui::Point(1, 16), "\bgMay cause poor performance with a lot of water"_i18n);
autowidth(tempLabel);
tempLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
tempLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
@ -105,14 +105,14 @@ OptionsView::OptionsView():
currentY+=19;
airMode = new ui::DropDown(ui::Point(Size.X-95, currentY), ui::Point(80, 16));
scrollPanel->AddChild(airMode);
airMode->AddOption(std::pair<String, int>("On", 0));
airMode->AddOption(std::pair<String, int>("Pressure off", 1));
airMode->AddOption(std::pair<String, int>("Velocity off", 2));
airMode->AddOption(std::pair<String, int>("Off", 3));
airMode->AddOption(std::pair<String, int>("No Update", 4));
airMode->AddOption({"On"_i18n, 0});
airMode->AddOption({"Pressure off"_i18n, 1});
airMode->AddOption({"Velocity off"_i18n, 2});
airMode->AddOption({"Off"_i18n, 3});
airMode->AddOption({"No Update"_i18n, 4});
airMode->SetActionCallback({ [this] { c->SetAirMode(airMode->GetOption().second); } });
tempLabel = new ui::Label(ui::Point(8, currentY), ui::Point(Size.X-96, 16), "Air Simulation Mode");
tempLabel = new ui::Label(ui::Point(8, currentY), ui::Point(Size.X-96, 16), "Air Simulation Mode"_i18n);
tempLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
tempLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
scrollPanel->AddChild(tempLabel);
@ -120,12 +120,12 @@ OptionsView::OptionsView():
currentY+=20;
gravityMode = new ui::DropDown(ui::Point(Size.X-95, currentY), ui::Point(80, 16));
scrollPanel->AddChild(gravityMode);
gravityMode->AddOption(std::pair<String, int>("Vertical", 0));
gravityMode->AddOption(std::pair<String, int>("Off", 1));
gravityMode->AddOption(std::pair<String, int>("Radial", 2));
gravityMode->AddOption({"Vertical"_i18n, 0});
gravityMode->AddOption({"Off"_i18n, 1});
gravityMode->AddOption({"Radial"_i18n, 2});
gravityMode->SetActionCallback({ [this] { c->SetGravityMode(gravityMode->GetOption().second); } });
tempLabel = new ui::Label(ui::Point(8, currentY), ui::Point(Size.X-96, 16), "Gravity Simulation Mode");
tempLabel = new ui::Label(ui::Point(8, currentY), ui::Point(Size.X-96, 16), "Gravity Simulation Mode"_i18n);
tempLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
tempLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
scrollPanel->AddChild(tempLabel);
@ -133,12 +133,12 @@ OptionsView::OptionsView():
currentY+=20;
edgeMode = new ui::DropDown(ui::Point(Size.X-95, currentY), ui::Point(80, 16));
scrollPanel->AddChild(edgeMode);
edgeMode->AddOption(std::pair<String, int>("Void", 0));
edgeMode->AddOption(std::pair<String, int>("Solid", 1));
edgeMode->AddOption(std::pair<String, int>("Loop", 2));
edgeMode->AddOption({"Void"_i18n, 0});
edgeMode->AddOption({"Solid"_i18n, 1});
edgeMode->AddOption({"Loop"_i18n, 2});
edgeMode->SetActionCallback({ [this] { c->SetEdgeMode(edgeMode->GetOption().second); } });
tempLabel = new ui::Label(ui::Point(8, currentY), ui::Point(Size.X-96, 16), "Edge Mode");
tempLabel = new ui::Label(ui::Point(8, currentY), ui::Point(Size.X-96, 16), "Edge Mode"_i18n);
tempLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
tempLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
scrollPanel->AddChild(tempLabel);
@ -157,26 +157,26 @@ OptionsView::OptionsView():
{
if (current_scale == ix_scale)
current_scale_valid = true;
scale->AddOption(std::pair<String, int>(String::Build(ix_scale), ix_scale));
scale->AddOption({String::Build(ix_scale), ix_scale});
ix_scale += 1;
}
while (ui::Engine::Ref().GetMaxWidth() >= ui::Engine::Ref().GetWidth() * ix_scale && ui::Engine::Ref().GetMaxHeight() >= ui::Engine::Ref().GetHeight() * ix_scale);
if (!current_scale_valid)
scale->AddOption(std::pair<String, int>("current", current_scale));
scale->AddOption({"current"_i18n, current_scale});
}
scale->SetActionCallback({ [this] { c->SetScale(scale->GetOption().second); } });
scrollPanel->AddChild(scale);
tempLabel = new ui::Label(ui::Point(scale->Position.X+scale->Size.X+3, currentY), ui::Point(Size.X-40, 16), "\bg- Window scale factor for larger screens");
tempLabel = new ui::Label(ui::Point(scale->Position.X+scale->Size.X+3, currentY), ui::Point(Size.X-40, 16), "\bg- Window scale factor for larger screens"_i18n);
tempLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
tempLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
scrollPanel->AddChild(tempLabel);
currentY+=20;
resizable = new ui::Checkbox(ui::Point(8, currentY), ui::Point(1, 16), "Resizable", "");
resizable = new ui::Checkbox(ui::Point(8, currentY), ui::Point(1, 16), "Resizable"_i18n, "");
autowidth(resizable);
resizable->SetActionCallback({ [this] { c->SetResizable(resizable->GetChecked()); } });
tempLabel = new ui::Label(ui::Point(resizable->Position.X+Graphics::textwidth(resizable->GetText())+20, currentY), ui::Point(1, 16), "\bg- Allow resizing and maximizing window");
tempLabel = new ui::Label(ui::Point(resizable->Position.X+Graphics::textwidth(resizable->GetText())+20, currentY), ui::Point(1, 16), "\bg- Allow resizing and maximizing window"_i18n);
autowidth(tempLabel);
tempLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
tempLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
@ -184,10 +184,10 @@ OptionsView::OptionsView():
scrollPanel->AddChild(resizable);
currentY+=20;
fullscreen = new ui::Checkbox(ui::Point(8, currentY), ui::Point(1, 16), "Fullscreen", "");
fullscreen = new ui::Checkbox(ui::Point(8, currentY), ui::Point(1, 16), "Fullscreen"_i18n, "");
autowidth(fullscreen);
fullscreen->SetActionCallback({ [this] { c->SetFullscreen(fullscreen->GetChecked()); } });
tempLabel = new ui::Label(ui::Point(fullscreen->Position.X+Graphics::textwidth(fullscreen->GetText())+20, currentY), ui::Point(1, 16), "\bg- Fill the entire screen");
tempLabel = new ui::Label(ui::Point(fullscreen->Position.X+Graphics::textwidth(fullscreen->GetText())+20, currentY), ui::Point(1, 16), "\bg- Fill the entire screen"_i18n);
autowidth(tempLabel);
tempLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
tempLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
@ -195,10 +195,10 @@ OptionsView::OptionsView():
scrollPanel->AddChild(fullscreen);
currentY+=20;
altFullscreen = new ui::Checkbox(ui::Point(23, currentY), ui::Point(1, 16), "Change Resolution", "");
altFullscreen = new ui::Checkbox(ui::Point(23, currentY), ui::Point(1, 16), "Change Resolution"_i18n, "");
autowidth(altFullscreen);
altFullscreen->SetActionCallback({ [this] { c->SetAltFullscreen(altFullscreen->GetChecked()); } });
tempLabel = new ui::Label(ui::Point(altFullscreen->Position.X+Graphics::textwidth(altFullscreen->GetText())+20, currentY), ui::Point(1, 16), "\bg- Set optimial screen resolution");
tempLabel = new ui::Label(ui::Point(altFullscreen->Position.X+Graphics::textwidth(altFullscreen->GetText())+20, currentY), ui::Point(1, 16), "\bg- Set optimal screen resolution"_i18n);
autowidth(tempLabel);
tempLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
tempLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
@ -206,10 +206,10 @@ OptionsView::OptionsView():
scrollPanel->AddChild(altFullscreen);
currentY+=20;
forceIntegerScaling = new ui::Checkbox(ui::Point(23, currentY), ui::Point(1, 16), "Force Integer Scaling", "");
forceIntegerScaling = new ui::Checkbox(ui::Point(23, currentY), ui::Point(1, 16), "Force Integer Scaling"_i18n, "");
autowidth(forceIntegerScaling);
forceIntegerScaling->SetActionCallback({ [this] { c->SetForceIntegerScaling(forceIntegerScaling->GetChecked()); } });
tempLabel = new ui::Label(ui::Point(altFullscreen->Position.X+Graphics::textwidth(forceIntegerScaling->GetText())+20, currentY), ui::Point(1, 16), "\bg- Less blurry");
tempLabel = new ui::Label(ui::Point(altFullscreen->Position.X+Graphics::textwidth(forceIntegerScaling->GetText())+20, currentY), ui::Point(1, 16), "\bg- Less blurry"_i18n);
autowidth(tempLabel);
tempLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
tempLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
@ -217,10 +217,10 @@ OptionsView::OptionsView():
scrollPanel->AddChild(forceIntegerScaling);
currentY+=20;
fastquit = new ui::Checkbox(ui::Point(8, currentY), ui::Point(1, 16), "Fast Quit", "");
fastquit = new ui::Checkbox(ui::Point(8, currentY), ui::Point(1, 16), "Fast Quit"_i18n, "");
autowidth(fastquit);
fastquit->SetActionCallback({ [this] { c->SetFastQuit(fastquit->GetChecked()); } });
tempLabel = new ui::Label(ui::Point(fastquit->Position.X+Graphics::textwidth(fastquit->GetText())+20, currentY), ui::Point(1, 16), "\bg- Always exit completely when hitting close");
tempLabel = new ui::Label(ui::Point(fastquit->Position.X+Graphics::textwidth(fastquit->GetText())+20, currentY), ui::Point(1, 16), "\bg- Always exit completely when hitting close"_i18n);
autowidth(tempLabel);
tempLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
tempLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
@ -228,10 +228,10 @@ OptionsView::OptionsView():
scrollPanel->AddChild(fastquit);
currentY+=20;
showAvatars = new ui::Checkbox(ui::Point(8, currentY), ui::Point(1, 16), "Show Avatars", "");
showAvatars = new ui::Checkbox(ui::Point(8, currentY), ui::Point(1, 16), "Show Avatars"_i18n, "");
autowidth(showAvatars);
showAvatars->SetActionCallback({ [this] { c->SetShowAvatars(showAvatars->GetChecked()); } });
tempLabel = new ui::Label(ui::Point(showAvatars->Position.X+Graphics::textwidth(showAvatars->GetText())+20, currentY), ui::Point(1, 16), "\bg- Disable if you have a slow connection");
tempLabel = new ui::Label(ui::Point(showAvatars->Position.X+Graphics::textwidth(showAvatars->GetText())+20, currentY), ui::Point(1, 16), "\bg- Disable if you have a slow connection"_i18n);
autowidth(tempLabel);
tempLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
tempLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
@ -239,10 +239,10 @@ OptionsView::OptionsView():
scrollPanel->AddChild(showAvatars);
currentY+=20;
mouseClickRequired = new ui::Checkbox(ui::Point(8, currentY), ui::Point(1, 16), "Sticky Categories", "");
mouseClickRequired = new ui::Checkbox(ui::Point(8, currentY), ui::Point(1, 16), "Sticky Categories"_i18n, "");
autowidth(mouseClickRequired);
mouseClickRequired->SetActionCallback({ [this] { c->SetMouseClickrequired(mouseClickRequired->GetChecked()); } });
tempLabel = new ui::Label(ui::Point(mouseClickRequired->Position.X+Graphics::textwidth(mouseClickRequired->GetText())+20, currentY), ui::Point(1, 16), "\bg- Switch between categories by clicking");
tempLabel = new ui::Label(ui::Point(mouseClickRequired->Position.X+Graphics::textwidth(mouseClickRequired->GetText())+20, currentY), ui::Point(1, 16), "\bg- Switch between categories by clicking"_i18n);
autowidth(tempLabel);
tempLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
tempLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
@ -250,10 +250,10 @@ OptionsView::OptionsView():
scrollPanel->AddChild(mouseClickRequired);
currentY+=20;
includePressure = new ui::Checkbox(ui::Point(8, currentY), ui::Point(1, 16), "Include Pressure", "");
includePressure = new ui::Checkbox(ui::Point(8, currentY), ui::Point(1, 16), "Include Pressure"_i18n, "");
autowidth(includePressure);
includePressure->SetActionCallback({ [this] { c->SetIncludePressure(includePressure->GetChecked()); } });
tempLabel = new ui::Label(ui::Point(includePressure->Position.X+Graphics::textwidth(includePressure->GetText())+20, currentY), ui::Point(1, 16), "\bg- When saving, copying, stamping, etc.");
tempLabel = new ui::Label(ui::Point(includePressure->Position.X+Graphics::textwidth(includePressure->GetText())+20, currentY), ui::Point(1, 16), "\bg- When saving, copying, stamping, etc."_i18n);
autowidth(tempLabel);
tempLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
tempLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
@ -261,10 +261,10 @@ OptionsView::OptionsView():
scrollPanel->AddChild(includePressure);
currentY+=20;
perfectCirclePressure = new ui::Checkbox(ui::Point(8, currentY), ui::Point(1, 16), "Perfect Circle", "");
perfectCirclePressure = new ui::Checkbox(ui::Point(8, currentY), ui::Point(1, 16), "Perfect Circle"_i18n, "");
autowidth(perfectCirclePressure);
perfectCirclePressure->SetActionCallback({ [this] { c->SetPerfectCircle(perfectCirclePressure->GetChecked()); } });
tempLabel = new ui::Label(ui::Point(perfectCirclePressure->Position.X+Graphics::textwidth(perfectCirclePressure->GetText())+20, currentY), ui::Point(1, 16), "\bg- Better circle brush, without incorrect points on edges");
tempLabel = new ui::Label(ui::Point(perfectCirclePressure->Position.X+Graphics::textwidth(perfectCirclePressure->GetText())+20, currentY), ui::Point(1, 16), "\bg- Better circle brush, without incorrect points on edges"_i18n);
autowidth(tempLabel);
tempLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
tempLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
@ -277,18 +277,18 @@ OptionsView::OptionsView():
decoSpace = new ui::DropDown(ui::Point(8, currentY), ui::Point(60, 16));
decoSpace->SetActionCallback({ [this] { c->SetDecoSpace(decoSpace->GetOption().second); } });
scrollPanel->AddChild(decoSpace);
decoSpace->AddOption(std::pair<String, int>("sRGB", 0));
decoSpace->AddOption(std::pair<String, int>("Linear", 1));
decoSpace->AddOption(std::pair<String, int>("Gamma 2.2", 2));
decoSpace->AddOption(std::pair<String, int>("Gamma 1.8", 3));
decoSpace->AddOption({"sRGB"_i18n, 0});
decoSpace->AddOption({"Linear"_i18n, 1});
decoSpace->AddOption({"Gamma 2.2"_i18n, 2});
decoSpace->AddOption({"Gamma 1.8"_i18n, 3});
tempLabel = new ui::Label(ui::Point(decoSpace->Position.X+decoSpace->Size.X+3, currentY), ui::Point(Size.X-40, 16), "\bg- Colour space used by decoration tools");
tempLabel = new ui::Label(ui::Point(decoSpace->Position.X+decoSpace->Size.X+3, currentY), ui::Point(Size.X-40, 16), "\bg- Colour space used by decoration tools"_i18n);
tempLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
tempLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
scrollPanel->AddChild(tempLabel);
currentY+=20;
ui::Button * dataFolderButton = new ui::Button(ui::Point(8, currentY), ui::Point(90, 16), "Open Data Folder");
ui::Button * dataFolderButton = new ui::Button(ui::Point(8, currentY), ui::Point(90, 16), "Open Data Folder"_i18n);
dataFolderButton->SetActionCallback({ [] {
//one of these should always be defined
#ifdef WIN
@ -306,13 +306,13 @@ OptionsView::OptionsView():
} });
scrollPanel->AddChild(dataFolderButton);
tempLabel = new ui::Label(ui::Point(dataFolderButton->Position.X+dataFolderButton->Size.X+3, currentY), ui::Point(1, 16), "\bg- Open the data and preferences folder");
tempLabel = new ui::Label(ui::Point(dataFolderButton->Position.X+dataFolderButton->Size.X+3, currentY), ui::Point(1, 16), "\bg- Open the data and preferences folder"_i18n);
autowidth(tempLabel);
tempLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
tempLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
scrollPanel->AddChild(tempLabel);
ui::Button * tempButton = new ui::Button(ui::Point(0, Size.Y-16), ui::Point(Size.X, 16), "OK");
ui::Button * tempButton = new ui::Button(ui::Point(0, Size.Y-16), ui::Point(Size.X, 16), "OK"_i18n);
tempButton->SetActionCallback({ [this] { c->Exit(); } });
AddComponent(tempButton);
SetCancelButton(tempButton);

View File

@ -58,7 +58,7 @@ bool PreviewController::SubmitComment(String comment)
{
if(comment.length() < 4)
{
new ErrorMessage("Error", "Comment is too short");
new ErrorMessage("Error"_i18n, "Comment is too short"_i18n);
return false;
}
else
@ -66,7 +66,7 @@ bool PreviewController::SubmitComment(String comment)
RequestStatus status = Client::Ref().AddComment(saveId, comment);
if(status != RequestOkay)
{
new ErrorMessage("Error submitting comment", Client::Ref().GetLastError());
new ErrorMessage("Error submitting comment"_i18n, Client::Ref().GetLastError());
return false;
}
else
@ -109,10 +109,10 @@ void PreviewController::Report(String message)
if(Client::Ref().ReportSave(saveId, message) == RequestOkay)
{
Exit();
new InformationMessage("Information", "Report submitted", false);
new InformationMessage("Information"_i18n, "Report submitted"_i18n, false);
}
else
new ErrorMessage("Error", "Unable to file report: " + Client::Ref().GetLastError());
new ErrorMessage("Error"_i18n, "Unable to file report: "_i18n + Client::Ref().GetLastError());
}
void PreviewController::FavouriteSave()
@ -128,7 +128,7 @@ void PreviewController::FavouriteSave()
}
catch (PreviewModelException & e)
{
new ErrorMessage("Error", ByteString(e.what()).FromUtf8());
new ErrorMessage("Error"_i18n, ByteString(e.what()).FromUtf8());
}
}
}

View File

@ -39,9 +39,9 @@ void PreviewModel::SetFavourite(bool favourite)
if (Client::Ref().FavouriteSave(saveInfo->id, favourite) == RequestOkay)
saveInfo->Favourite = favourite;
else if (favourite)
throw PreviewModelException("Error, could not fav. the save: " + Client::Ref().GetLastError());
throw PreviewModelException("Error, could not fav. the save: "_i18n + Client::Ref().GetLastError());
else
throw PreviewModelException("Error, could not unfav. the save: " + Client::Ref().GetLastError());
throw PreviewModelException("Error, could not unfav. the save: "_i18n + Client::Ref().GetLastError());
notifySaveChanged();
}
}
@ -175,12 +175,12 @@ void PreviewModel::OnSaveReady()
{
GameSave *gameSave = new GameSave(*saveData);
if (gameSave->fromNewerVersion)
new ErrorMessage("This save is from a newer version", "Please update TPT in game or at https://powdertoy.co.uk");
new ErrorMessage("This save is from a newer version"_i18n, "Please update TPT in game or at "_i18n + ByteString(SCHEME SERVER).FromAscii());
saveInfo->SetGameSave(gameSave);
}
catch(ParseException &e)
{
new ErrorMessage("Error", ByteString(e.what()).FromUtf8());
new ErrorMessage("Error"_i18n, ByteString(e.what()).FromUtf8());
canOpen = false;
}
notifySaveChanged();
@ -331,7 +331,7 @@ void PreviewModel::Update()
else
{
for (size_t i = 0; i < observers.size(); i++)
observers[i]->SaveLoadingError("Could not parse save info");
observers[i]->SaveLoadingError("Could not parse save info"_i18n);
}
}
else

View File

@ -4,6 +4,7 @@
#include "client/Client.h"
#include "client/SaveInfo.h"
#include "client/MD5.h"
#include "gui/dialogues/TextPrompt.h"
#include "gui/profile/ProfileActivity.h"
@ -43,11 +44,22 @@ PreviewView::PreviewView():
showAvatars(true),
prevPage(false),
commentBoxHeight(20),
commentHelpText(false)
commentHelpText(false),
swearWords{
{"99754106633f94d350db34d548d6091a", 4},
{"316928e0d260556eaccb6627f2ed657b", 5},
{"78b34eebadbdb3d7d9b4e4833598623a", 5},
{"0b9a54438fba2dc0d39be8f7c6c71a58", 7},
{"7f55a0ed8b021080de00960cc73768fb", 4},
{"b52b073595ccb35eaebb87178227b779", 4},
{"a3198e07522baec3f48fac455926cba2", 7},
{"cb205edee16b24366c871cf55e781346", 6},
{"b529d8871187ecc7fe5f152142b3440a", 7},
}
{
showAvatars = Client::Ref().GetPrefBool("ShowAvatars", true);
favButton = new ui::Button(ui::Point(50, Size.Y-19), ui::Point(51, 19), "Fav");
favButton = new ui::Button(ui::Point(50, Size.Y-19), ui::Point(51, 19), "Fav"_i18n);
favButton->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
favButton->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
favButton->SetIcon(IconFavourite);
@ -55,26 +67,26 @@ PreviewView::PreviewView():
favButton->Enabled = Client::Ref().GetAuthUser().UserID?true:false;
AddComponent(favButton);
reportButton = new ui::Button(ui::Point(100, Size.Y-19), ui::Point(51, 19), "Report");
reportButton = new ui::Button(ui::Point(100, Size.Y-19), ui::Point(51, 19), "Report"_i18n);
reportButton->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
reportButton->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
reportButton->SetIcon(IconReport);
reportButton->SetActionCallback({ [this] {
new TextPrompt("Report Save", "Things to consider when reporting:\n\bw1)\bg When reporting stolen saves, please include the ID of the original save.\n\bw2)\bg Do not ask for saves to be removed from front page unless they break the rules.\n\bw3)\bg You may report saves for comments or tags too (including your own saves)", "", "[reason]", true, { [this](String const &resultText) {
new TextPrompt("Report Save"_i18n, "Things to consider when reporting:\n\bw1)\bg When reporting stolen saves, please include the ID of the original save.\n\bw2)\bg Do not ask for saves to be removed from front page unless they break the rules.\n\bw3)\bg You may report saves for comments or tags too (including your own saves)"_i18n, "", "[reason]"_i18n, true, { [this](String const &resultText) {
c->Report(resultText);
} });
} });
reportButton->Enabled = Client::Ref().GetAuthUser().UserID?true:false;
AddComponent(reportButton);
openButton = new ui::Button(ui::Point(0, Size.Y-19), ui::Point(51, 19), "Open");
openButton = new ui::Button(ui::Point(0, Size.Y-19), ui::Point(51, 19), "Open"_i18n);
openButton->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
openButton->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
openButton->SetIcon(IconOpen);
openButton->SetActionCallback({ [this] { c->DoOpen(); } });
AddComponent(openButton);
browserOpenButton = new ui::Button(ui::Point((XRES/2)-107, Size.Y-19), ui::Point(108, 19), "Open in browser");
browserOpenButton = new ui::Button(ui::Point((XRES/2)-107, Size.Y-19), ui::Point(108, 19), "Open in browser"_i18n);
browserOpenButton->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
browserOpenButton->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
browserOpenButton->SetIcon(IconOpen);
@ -124,36 +136,26 @@ PreviewView::PreviewView():
viewsLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
AddComponent(viewsLabel);
pageInfo = new ui::Label(ui::Point((XRES/2) + 85, Size.Y+1), ui::Point(70, 16), "Page 1 of 1");
pageInfo = new ui::Label(ui::Point((XRES/2) + 85, Size.Y+1), ui::Point(70, 16), "");
pageInfo->Appearance.HorizontalAlign = ui::Appearance::AlignCentre;
AddComponent(pageInfo);
commentsPanel = new ui::ScrollPanel(ui::Point((XRES/2)+1, 1), ui::Point((Size.X-(XRES/2))-2, Size.Y-commentBoxHeight));
AddComponent(commentsPanel);
swearWords.insert("fuck");
swearWords.insert("bitch");
swearWords.insert("shit ");
swearWords.insert("asshole");
swearWords.insert("dick");
swearWords.insert("cunt");
swearWords.insert(" nigger");
swearWords.insert("faggot");
swearWords.insert("dumbass");
}
void PreviewView::AttachController(PreviewController * controller)
{
c = controller;
int textWidth = Graphics::textwidth("Click the box below to copy the save ID");
saveIDLabel = new ui::Label(ui::Point((Size.X-textWidth-20)/2, Size.Y+5), ui::Point(textWidth+20, 16), "Click the box below to copy the save ID");
int textWidth = Graphics::textwidth("Click the box below to copy the save ID"_i18n);
saveIDLabel = new ui::Label(ui::Point((Size.X-textWidth-20)/2, Size.Y+5), ui::Point(textWidth+20, 16), "Click the box below to copy the save ID"_i18n);
saveIDLabel->SetTextColour(ui::Colour(150, 150, 150));
saveIDLabel->Appearance.HorizontalAlign = ui::Appearance::AlignCentre;
AddComponent(saveIDLabel);
textWidth = Graphics::textwidth(String::Build(c->SaveID()));
saveIDLabel2 = new ui::Label(ui::Point((Size.X-textWidth-20)/2-37, Size.Y+22), ui::Point(40, 16), "Save ID:");
saveIDLabel2 = new ui::Label(ui::Point((Size.X-textWidth-20)/2-37, Size.Y+22), ui::Point(40, 16), "Save ID:"_i18n);
AddComponent(saveIDLabel2);
saveIDButton = new ui::CopyTextButton(ui::Point((Size.X-textWidth-10)/2, Size.Y+20), ui::Point(textWidth+10, 18), String::Build(c->SaveID()), saveIDLabel);
@ -204,9 +206,15 @@ void PreviewView::commentBoxAutoHeight()
bool PreviewView::CheckSwearing(String text)
{
for (std::set<String>::iterator iter = swearWords.begin(), end = swearWords.end(); iter != end; iter++)
if (text.Contains(*iter))
return true;
char hash[33];
ByteString bytes = text.ToUtf8();
for(auto const &pair : swearWords)
for(size_t i = 0; i + pair.second <= bytes.length(); i++)
{
md5(hash, (unsigned char *)(bytes.data() + i), pair.second);
if(pair.first == hash)
return true;
}
return false;
}
@ -220,15 +228,15 @@ void PreviewView::CheckComment()
if (!commentHelpText)
{
if (random_gen()%2)
commentWarningLabel->SetText("Stolen? Report the save instead");
commentWarningLabel->SetText("Stolen? Report the save instead"_i18n);
else
commentWarningLabel->SetText("Please report stolen saves");
commentWarningLabel->SetText("Please report stolen saves"_i18n);
commentHelpText = true;
}
}
else if (userIsAuthor && text.Contains("vote"))
{
commentWarningLabel->SetText("Do not ask for votes");
commentWarningLabel->SetText("Do not ask for votes"_i18n);
commentHelpText = true;
}
else if (CheckSwearing(text))
@ -236,9 +244,9 @@ void PreviewView::CheckComment()
if (!commentHelpText)
{
if (random_gen()%2)
commentWarningLabel->SetText("Please do not swear");
commentWarningLabel->SetText("Please do not swear"_i18n);
else
commentWarningLabel->SetText("Bad language may be deleted");
commentWarningLabel->SetText("Bad language may be deleted"_i18n);
commentHelpText = true;
}
}
@ -268,7 +276,7 @@ void PreviewView::DoDraw()
{
g->fillrect(Position.X+(Size.X/2)-101, Position.Y+(Size.Y/2)-26, 202, 52, 0, 0, 0, 210);
g->drawrect(Position.X+(Size.X/2)-100, Position.Y+(Size.Y/2)-25, 200, 50, 255, 255, 255, 180);
g->drawtext(Position.X+(Size.X/2)-(Graphics::textwidth("Loading save...")/2), Position.Y+(Size.Y/2)-5, "Loading save...", style::Colour::InformationTitle.Red, style::Colour::InformationTitle.Green, style::Colour::InformationTitle.Blue, 255);
g->drawtext(Position.X+(Size.X/2)-(Graphics::textwidth("Loading save..."_i18n)/2), Position.Y+(Size.Y/2)-5, "Loading save..."_i18n, style::Colour::InformationTitle.Red, style::Colour::InformationTitle.Green, style::Colour::InformationTitle.Blue, 255);
}
g->drawrect(Position.X, Position.Y, Size.X, Size.Y, 255, 255, 255, 255);
@ -367,7 +375,7 @@ void PreviewView::OnTick(float dt)
c->Update();
if (doError)
{
ErrorMessage::Blocking("Error loading save", doErrorMessage);
ErrorMessage::Blocking("Error loading save"_i18n, doErrorMessage);
c->Exit();
}
}
@ -424,9 +432,9 @@ void PreviewView::NotifySaveChanged(PreviewModel * sender)
saveNameLabel->SetText(save->name);
String dateType;
if (save->updatedDate == save->createdDate)
dateType = "Created:";
dateType = "Created:"_i18n;
else
dateType = "Updated:";
dateType = "Updated:"_i18n;
if (showAvatars)
{
avatarButton->SetUsername(save->userName);
@ -434,27 +442,27 @@ void PreviewView::NotifySaveChanged(PreviewModel * sender)
}
else
{
authorDateLabel->SetText("\bgAuthor:\bw " + save->userName.FromUtf8() + " \bg" + dateType + " \bw" + format::UnixtimeToDateMini(save->updatedDate).FromAscii());
authorDateLabel->SetText("\bgAuthor:\bw "_i18n + save->userName.FromUtf8() + " \bg" + dateType + " \bw" + format::UnixtimeToDateMini(save->updatedDate).FromAscii());
}
if (Client::Ref().GetAuthUser().UserID && save->userName == Client::Ref().GetAuthUser().Username)
userIsAuthor = true;
else
userIsAuthor = false;
viewsLabel->SetText(String::Build("\bgViews:\bw ", save->Views));
viewsLabel->SetText(String::Build("\bgViews:\bw "_i18n, save->Views));
saveDescriptionLabel->SetText(save->Description);
if(save->Favourite)
{
favButton->Enabled = true;
favButton->SetText("Unfav");
favButton->SetText("Unfav"_i18n);
}
else if(Client::Ref().GetAuthUser().UserID)
{
favButton->Enabled = true;
favButton->SetText("Fav");
favButton->SetText("Fav"_i18n);
}
else
{
favButton->SetText("Fav");
favButton->SetText("Fav"_i18n);
favButton->Enabled = false;
}
@ -498,13 +506,13 @@ void PreviewView::submitComment()
String comment = addCommentBox->GetText();
submitCommentButton->Enabled = false;
addCommentBox->SetText("");
addCommentBox->SetPlaceholder("Submitting comment"); //This doesn't appear to ever show since no separate thread is created
addCommentBox->SetPlaceholder("Submitting comment"_i18n); //This doesn't appear to ever show since no separate thread is created
FocusComponent(NULL);
if (!c->SubmitComment(comment))
addCommentBox->SetText(comment);
addCommentBox->SetPlaceholder("Add comment");
addCommentBox->SetPlaceholder("Add comment"_i18n);
submitCommentButton->Enabled = true;
commentBoxAutoHeight();
@ -532,7 +540,7 @@ void PreviewView::NotifyCommentBoxEnabledChanged(PreviewModel * sender)
commentBoxSizeX = Size.X-(XRES/2)-48;
commentBoxSizeY = 17;
addCommentBox = new ui::Textbox(ui::Point((XRES/2)+4, Size.Y-19), ui::Point(Size.X-(XRES/2)-48, 17), "", "Add Comment");
addCommentBox = new ui::Textbox(ui::Point((XRES/2)+4, Size.Y-19), ui::Point(Size.X-(XRES/2)-48, 17), "", "Add Comment"_i18n);
addCommentBox->SetActionCallback({ [this] {
CheckComment();
commentBoxAutoHeight();
@ -540,12 +548,12 @@ void PreviewView::NotifyCommentBoxEnabledChanged(PreviewModel * sender)
addCommentBox->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
addCommentBox->SetMultiline(true);
AddComponent(addCommentBox);
submitCommentButton = new ui::Button(ui::Point(Size.X-40, Size.Y-19), ui::Point(40, 19), "Submit");
submitCommentButton = new ui::Button(ui::Point(Size.X-40, Size.Y-19), ui::Point(40, 19), "Submit"_i18n);
submitCommentButton->SetActionCallback({ [this] { submitComment(); } });
//submitCommentButton->Enabled = false;
AddComponent(submitCommentButton);
commentWarningLabel = new ui::Label(ui::Point((XRES/2)+4, Size.Y-19), ui::Point(Size.X-(XRES/2)-48, 16), "If you see this it is a bug");
commentWarningLabel = new ui::Label(ui::Point((XRES/2)+4, Size.Y-19), ui::Point(Size.X-(XRES/2)-48, 16), "If you see this it is a bug"_i18n);
commentWarningLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
commentWarningLabel->SetTextColour(ui::Colour(255, 0, 0));
commentWarningLabel->Visible = false;
@ -553,7 +561,7 @@ void PreviewView::NotifyCommentBoxEnabledChanged(PreviewModel * sender)
}
else
{
submitCommentButton = new ui::Button(ui::Point(XRES/2, Size.Y-19), ui::Point(Size.X-(XRES/2), 19), "Login to comment");
submitCommentButton = new ui::Button(ui::Point(XRES/2, Size.Y-19), ui::Point(Size.X-(XRES/2), 19), "Login to comment"_i18n);
submitCommentButton->SetActionCallback({ [this] { c->ShowLogin(); } });
AddComponent(submitCommentButton);
}
@ -567,7 +575,8 @@ void PreviewView::SaveLoadingError(String errorMessage)
void PreviewView::NotifyCommentsPageChanged(PreviewModel * sender)
{
pageInfo->SetText(String::Build("Page ", sender->GetCommentsPageNum(), " of ", sender->GetCommentsPageCount()));
auto pageOf = i18nMulti("Page ", " of ");
pageInfo->SetText(String::Build(pageOf[0], sender->GetCommentsPageNum(), pageOf[1], sender->GetCommentsPageCount()));
}
void PreviewView::NotifyCommentsChanged(PreviewModel * sender)

View File

@ -58,7 +58,7 @@ class PreviewView: public ui::Window
float commentBoxSizeY;
bool commentHelpText;
std::set<String> swearWords;
std::map<ByteString, size_t> swearWords; // MD5(word), len(word)
void displayComments();
void commentBoxAutoHeight();

View File

@ -21,7 +21,7 @@ ProfileActivity::ProfileActivity(ByteString username) :
{
editable = Client::Ref().GetAuthUser().UserID && Client::Ref().GetAuthUser().Username == username;
ui::Button * closeButton = new ui::Button(ui::Point(0, Size.Y-15), ui::Point(Size.X, 15), "Close");
ui::Button * closeButton = new ui::Button(ui::Point(0, Size.Y-15), ui::Point(Size.X, 15), "Close"_i18n);
closeButton->SetActionCallback({ [this] {
Exit();
} });
@ -29,12 +29,12 @@ ProfileActivity::ProfileActivity(ByteString username) :
{
closeButton->Size.X = (Size.X/2)+1;
ui::Button * saveButton = new ui::Button(ui::Point(Size.X/2, Size.Y-15), ui::Point(Size.X/2, 15), "Save");
ui::Button * saveButton = new ui::Button(ui::Point(Size.X/2, Size.Y-15), ui::Point(Size.X/2, 15), "Save"_i18n);
saveButton->SetActionCallback({ [this, saveButton] {
if (!loading && !saving && editable)
{
saveButton->Enabled = false;
saveButton->SetText("Saving...");
saveButton->SetText("Saving..."_i18n);
saving = true;
info.location = location->GetText();
info.biography = bio->GetText();
@ -58,11 +58,11 @@ void ProfileActivity::setUserInfo(UserInfo newInfo)
info = newInfo;
if (!info.biography.length() && !editable)
info.biography = "\bgNot Provided";
info.biography = "\bgNot Provided"_i18n;
if (!info.location.length() && !editable)
info.location = "\bgNot Provided";
info.location = "\bgNot Provided"_i18n;
if (!info.website.length())
info.website = "\bgNot Provided";
info.website = "\bgNot Provided"_i18n;
// everything is on a large scroll panel
scrollPanel = new ui::ScrollPanel(ui::Point(1, 1), ui::Point(Size.X-2, Size.Y-16));
@ -81,7 +81,7 @@ void ProfileActivity::setUserInfo(UserInfo newInfo)
// edit avatar button
if (editable)
{
ui::Button * editAvatar = new ui::Button(ui::Point(Size.X - (40 + 16 + 75), currentY), ui::Point(75, 15), "Edit Avatar");
ui::Button * editAvatar = new ui::Button(ui::Point(Size.X - (40 + 16 + 75), currentY), ui::Point(75, 15), "Edit Avatar"_i18n);
editAvatar->SetActionCallback({ [] {
Platform::OpenURI(SCHEME SERVER "/Profile/Avatar.html");
} });
@ -90,19 +90,19 @@ void ProfileActivity::setUserInfo(UserInfo newInfo)
currentY += 23;
// age
ui::Label * ageTitle = new ui::Label(ui::Point(4, currentY), ui::Point(18, 15), "Age:");
ui::Label * ageTitle = new ui::Label(ui::Point(4, currentY), ui::Point(18, 15), "Age:"_i18n);
ageTitle->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
ageTitle->SetTextColour(ui::Colour(180, 180, 180));
scrollPanel->AddChild(ageTitle);
// can't figure out how to tell a null from a 0 in the json library we use
ui::Label *age = new ui::Label(ui::Point(8+ageTitle->Size.X, currentY), ui::Point(40, 15), info.age ? String::Build(info.age) : "\bgNot Provided");
ui::Label *age = new ui::Label(ui::Point(8+ageTitle->Size.X, currentY), ui::Point(40, 15), info.age ? String::Build(info.age) : "\bgNot Provided"_i18n);
age->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
scrollPanel->AddChild(age);
currentY += 2+age->Size.Y;
// location
ui::Label * locationTitle = new ui::Label(ui::Point(4, currentY), ui::Point(45, 15), "Location:");
ui::Label * locationTitle = new ui::Label(ui::Point(4, currentY), ui::Point(45, 15), "Location:"_i18n);
locationTitle->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
locationTitle->SetTextColour(ui::Colour(180, 180, 180));
scrollPanel->AddChild(locationTitle);
@ -116,25 +116,25 @@ void ProfileActivity::setUserInfo(UserInfo newInfo)
currentY += 2+location->Size.Y;
// website
ui::Label * websiteTitle = new ui::Label(ui::Point(4, currentY), ui::Point(38, 15), "Website:");
ui::Label * websiteTitle = new ui::Label(ui::Point(4, currentY), ui::Point(38, 15), "Website:"_i18n);
websiteTitle->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
websiteTitle->SetTextColour(ui::Colour(180, 180, 180));
scrollPanel->AddChild(websiteTitle);
ui::Label *website = new ui::Label(ui::Point(8+websiteTitle->Size.X, currentY), ui::Point(Size.X-websiteTitle->Size.X-16, 15), info.website.FromUtf8());
ui::Label *website = new ui::Label(ui::Point(8+websiteTitle->Size.X, currentY), ui::Point(Size.X-websiteTitle->Size.X-16, 15), info.website);
website->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
scrollPanel->AddChild(website);
currentY += 2+website->Size.Y;
// saves
ui::Label * savesTitle = new ui::Label(ui::Point(4, currentY), ui::Point(35, 15), "Saves:");
ui::Label * savesTitle = new ui::Label(ui::Point(4, currentY), ui::Point(35, 15), "Saves:"_i18n);
savesTitle->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
savesTitle->SetTextColour(ui::Colour(180, 180, 180));
scrollPanel->AddChild(savesTitle);
currentY += savesTitle->Size.Y;
// saves count
ui::Label * saveCountTitle = new ui::Label(ui::Point(12, currentY), ui::Point(30, 15), "Count:");
ui::Label * saveCountTitle = new ui::Label(ui::Point(12, currentY), ui::Point(30, 15), "Count:"_i18n);
saveCountTitle->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
saveCountTitle->SetTextColour(ui::Colour(180, 180, 180));
scrollPanel->AddChild(saveCountTitle);
@ -145,7 +145,7 @@ void ProfileActivity::setUserInfo(UserInfo newInfo)
currentY += savesCount->Size.Y;
// average score
ui::Label * averageScoreTitle = new ui::Label(ui::Point(12, currentY), ui::Point(70, 15), "Average Score:");
ui::Label * averageScoreTitle = new ui::Label(ui::Point(12, currentY), ui::Point(70, 15), "Average Score:"_i18n);
averageScoreTitle->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
averageScoreTitle->SetTextColour(ui::Colour(180, 180, 180));
scrollPanel->AddChild(averageScoreTitle);
@ -156,7 +156,7 @@ void ProfileActivity::setUserInfo(UserInfo newInfo)
currentY += averageScore->Size.Y;
// highest score
ui::Label * highestScoreTitle = new ui::Label(ui::Point(12, currentY), ui::Point(69, 15), "Highest Score:");
ui::Label * highestScoreTitle = new ui::Label(ui::Point(12, currentY), ui::Point(69, 15), "Highest Score:"_i18n);
highestScoreTitle->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
highestScoreTitle->SetTextColour(ui::Colour(180, 180, 180));
scrollPanel->AddChild(highestScoreTitle);
@ -167,7 +167,7 @@ void ProfileActivity::setUserInfo(UserInfo newInfo)
currentY += 2+highestScore->Size.Y;
// biograhy
ui::Label * bioTitle = new ui::Label(ui::Point(4, currentY), ui::Point(50, 15), "Biography:");
ui::Label * bioTitle = new ui::Label(ui::Point(4, currentY), ui::Point(50, 15), "Biography:"_i18n);
bioTitle->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
bioTitle->SetTextColour(ui::Colour(180, 180, 180));
scrollPanel->AddChild(bioTitle);
@ -201,7 +201,7 @@ void ProfileActivity::OnResponse(bool SaveUserInfoStatus)
else
{
doError = true;
doErrorMessage = "Could not save user info: " + Client::Ref().GetLastError();
doErrorMessage = "Could not save user info: "_i18n + Client::Ref().GetLastError();
}
}
@ -215,7 +215,7 @@ void ProfileActivity::OnResponse(std::unique_ptr<UserInfo> getUserInfoResult)
else
{
doError = true;
doErrorMessage = "Could not load user info: " + Client::Ref().GetLastError();
doErrorMessage = "Could not load user info: "_i18n + Client::Ref().GetLastError();
}
}
@ -223,7 +223,7 @@ void ProfileActivity::OnTick(float dt)
{
if (doError)
{
ErrorMessage::Blocking("Error", doErrorMessage);
ErrorMessage::Blocking("Error"_i18n, doErrorMessage);
Exit();
}

View File

@ -31,17 +31,17 @@ RenderView::RenderView():
presetButton->SetActionCallback({ [this, index] { c->LoadRenderPreset(index); } });
AddComponent(presetButton);
};
addPresetButton( 1, IconVelocity , ui::Point( -37, 6), "Velocity display mode preset");
addPresetButton( 2, IconPressure , ui::Point( -37, 24), "Pressure display mode preset");
addPresetButton( 3, IconPersistant, ui::Point( -76, 6), "Persistent display mode preset");
addPresetButton( 4, IconFire , ui::Point( -76, 24), "Fire display mode preset");
addPresetButton( 5, IconBlob , ui::Point(-115, 6), "Blob display mode preset");
addPresetButton( 6, IconHeat , ui::Point(-115, 24), "Heat display mode preset");
addPresetButton( 7, IconBlur , ui::Point(-154, 6), "Fancy display mode preset");
addPresetButton( 8, IconBasic , ui::Point(-154, 24), "Nothing display mode preset");
addPresetButton( 9, IconGradient , ui::Point(-193, 6), "Heat gradient display mode preset");
addPresetButton( 0, IconAltAir , ui::Point(-193, 24), "Alternative Velocity display mode preset");
addPresetButton(10, IconLife , ui::Point(-232, 6), "Life display mode preset");
addPresetButton( 1, IconVelocity , ui::Point( -37, 6), "Velocity display mode preset"_i18n);
addPresetButton( 2, IconPressure , ui::Point( -37, 24), "Pressure display mode preset"_i18n);
addPresetButton( 3, IconPersistant, ui::Point( -76, 6), "Persistent display mode preset"_i18n);
addPresetButton( 4, IconFire , ui::Point( -76, 24), "Fire display mode preset"_i18n);
addPresetButton( 5, IconBlob , ui::Point(-115, 6), "Blob display mode preset"_i18n);
addPresetButton( 6, IconHeat , ui::Point(-115, 24), "Heat display mode preset"_i18n);
addPresetButton( 7, IconBlur , ui::Point(-154, 6), "Fancy display mode preset"_i18n);
addPresetButton( 8, IconBasic , ui::Point(-154, 24), "Nothing display mode preset"_i18n);
addPresetButton( 9, IconGradient , ui::Point(-193, 6), "Heat gradient display mode preset"_i18n);
addPresetButton( 0, IconAltAir , ui::Point(-193, 24), "Alternative Velocity display mode preset"_i18n);
addPresetButton(10, IconLife , ui::Point(-232, 6), "Life display mode preset"_i18n);
auto addRenderModeCheckbox = [this](unsigned int mode, Icon icon, ui::Point offset, String tooltip) {
auto *renderModeCheckbox = new ModeCheckbox(ui::Point(0, YRES) + offset, ui::Point(30, 16), "", tooltip);
@ -56,13 +56,13 @@ RenderView::RenderView():
} });
AddComponent(renderModeCheckbox);
};
addRenderModeCheckbox(RENDER_EFFE, IconEffect, ui::Point( 1, 4), "Adds Special flare effects to some elements");
addRenderModeCheckbox(RENDER_FIRE, IconFire , ui::Point( 1, 22), "Fire effect for gasses");
addRenderModeCheckbox(RENDER_GLOW, IconGlow , ui::Point(33, 4), "Glow effect on some elements");
addRenderModeCheckbox(RENDER_BLUR, IconBlur , ui::Point(33, 22), "Blur effect for liquids");
addRenderModeCheckbox(RENDER_BLOB, IconBlob , ui::Point(65, 4), "Makes everything be drawn like a blob");
addRenderModeCheckbox(RENDER_BASC, IconBasic , ui::Point(65, 22), "Basic rendering, without this, most things will be invisible");
addRenderModeCheckbox(RENDER_SPRK, IconEffect, ui::Point(97, 4), "Glow effect on sparks");
addRenderModeCheckbox(RENDER_EFFE, IconEffect, ui::Point( 1, 4), "Adds Special flare effects to some elements"_i18n);
addRenderModeCheckbox(RENDER_FIRE, IconFire , ui::Point( 1, 22), "Fire effect for gasses"_i18n);
addRenderModeCheckbox(RENDER_GLOW, IconGlow , ui::Point(33, 4), "Glow effect on some elements"_i18n);
addRenderModeCheckbox(RENDER_BLUR, IconBlur , ui::Point(33, 22), "Blur effect for liquids"_i18n);
addRenderModeCheckbox(RENDER_BLOB, IconBlob , ui::Point(65, 4), "Makes everything be drawn like a blob"_i18n);
addRenderModeCheckbox(RENDER_BASC, IconBasic , ui::Point(65, 22), "Basic rendering, without this, most things will be invisible"_i18n);
addRenderModeCheckbox(RENDER_SPRK, IconEffect, ui::Point(97, 4), "Glow effect on sparks"_i18n);
auto addDisplayModeCheckbox = [this](unsigned int mode, Icon icon, ui::Point offset, String tooltip) {
auto *displayModeCheckbox = new ModeCheckbox(ui::Point(0, YRES) + offset, ui::Point(30, 16), "", tooltip);
@ -78,20 +78,20 @@ RenderView::RenderView():
AddComponent(displayModeCheckbox);
};
line1 = 130;
addDisplayModeCheckbox(DISPLAY_AIRC, IconAltAir , ui::Point(135, 4), "Displays pressure as red and blue, and velocity as white");
addDisplayModeCheckbox(DISPLAY_AIRP, IconPressure , ui::Point(135, 22), "Displays pressure, red is positive and blue is negative");
addDisplayModeCheckbox(DISPLAY_AIRV, IconVelocity , ui::Point(167, 4), "Displays velocity and positive pressure: up/down adds blue, right/left adds red, still pressure adds green");
addDisplayModeCheckbox(DISPLAY_AIRH, IconHeat , ui::Point(167, 22), "Displays the temperature of the air like heat display does");
addDisplayModeCheckbox(DISPLAY_AIRC, IconAltAir , ui::Point(135, 4), "Displays pressure as red and blue, and velocity as white"_i18n);
addDisplayModeCheckbox(DISPLAY_AIRP, IconPressure , ui::Point(135, 22), "Displays pressure, red is positive and blue is negative"_i18n);
addDisplayModeCheckbox(DISPLAY_AIRV, IconVelocity , ui::Point(167, 4), "Displays velocity and positive pressure: up/down adds blue, right/left adds red, still pressure adds green"_i18n);
addDisplayModeCheckbox(DISPLAY_AIRH, IconHeat , ui::Point(167, 22), "Displays the temperature of the air like heat display does"_i18n);
line2 = 200;
addDisplayModeCheckbox(DISPLAY_WARP, IconWarp , ui::Point(205, 22), "Gravity lensing, Newtonian Gravity bends light with this on");
addDisplayModeCheckbox(DISPLAY_WARP, IconWarp , ui::Point(205, 22), "Gravity lensing, Newtonian Gravity bends light with this on"_i18n);
#ifdef OGLR
# define TOOLTIP "Some type of OpenGL effect ... maybe"
# define TOOLTIP "Some type of OpenGL effect ... maybe"_i18n
#else
# define TOOLTIP "Enables moving solids, stickmen guns, and premium(tm) graphics"
# define TOOLTIP "Enables moving solids, stickmen guns, and premium(tm) graphics"_i18n
#endif
addDisplayModeCheckbox(DISPLAY_EFFE, IconEffect , ui::Point(205, 4), TOOLTIP);
#undef TOOLTIP
addDisplayModeCheckbox(DISPLAY_PERS, IconPersistant, ui::Point(237, 4), "Element paths persist on the screen for a while");
addDisplayModeCheckbox(DISPLAY_PERS, IconPersistant, ui::Point(237, 4), "Element paths persist on the screen for a while"_i18n);
line3 = 270;
auto addColourModeCheckbox = [this](unsigned int mode, Icon icon, ui::Point offset, String tooltip) {
@ -107,10 +107,10 @@ RenderView::RenderView():
} });
AddComponent(colourModeCheckbox);
};
addColourModeCheckbox(COLOUR_HEAT, IconHeat , ui::Point(275, 4), "Displays temperatures of the elements, dark blue is coldest, pink is hottest");
addColourModeCheckbox(COLOUR_LIFE, IconLife , ui::Point(275, 22), "Displays the life value of elements in greyscale gradients");
addColourModeCheckbox(COLOUR_GRAD, IconGradient, ui::Point(307, 22), "Changes colors of elements slightly to show heat diffusing through them");
addColourModeCheckbox(COLOUR_BASC, IconBasic , ui::Point(307, 4), "No special effects at all for anything, overrides all other options and deco");
addColourModeCheckbox(COLOUR_HEAT, IconHeat , ui::Point(275, 4), "Displays temperatures of the elements, dark blue is coldest, pink is hottest"_i18n);
addColourModeCheckbox(COLOUR_LIFE, IconLife , ui::Point(275, 22), "Displays the life value of elements in greyscale gradients"_i18n);
addColourModeCheckbox(COLOUR_GRAD, IconGradient, ui::Point(307, 22), "Changes colors of elements slightly to show heat diffusing through them"_i18n);
addColourModeCheckbox(COLOUR_BASC, IconBasic , ui::Point(307, 4), "No special effects at all for anything, overrides all other options and deco"_i18n);
line4 = 340;
}

View File

@ -22,19 +22,19 @@ LocalSaveActivity::LocalSaveActivity(SaveFile save, OnSaved onSaved_) :
thumbnailRenderer(nullptr),
onSaved(onSaved_)
{
ui::Label * titleLabel = new ui::Label(ui::Point(4, 5), ui::Point(Size.X-8, 16), "Save to computer:");
ui::Label * titleLabel = new ui::Label(ui::Point(4, 5), ui::Point(Size.X-8, 16), "Save to computer:"_i18n);
titleLabel->SetTextColour(style::Colour::InformationTitle);
titleLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
titleLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
AddComponent(titleLabel);
filenameField = new ui::Textbox(ui::Point(8, 25), ui::Point(Size.X-16, 16), save.GetDisplayName(), "[filename]");
filenameField = new ui::Textbox(ui::Point(8, 25), ui::Point(Size.X-16, 16), save.GetDisplayName(), "[filename]"_i18n);
filenameField->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
filenameField->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
AddComponent(filenameField);
FocusComponent(filenameField);
ui::Button * cancelButton = new ui::Button(ui::Point(0, Size.Y-16), ui::Point(Size.X-75, 16), "Cancel");
ui::Button * cancelButton = new ui::Button(ui::Point(0, Size.Y-16), ui::Point(Size.X-75, 16), "Cancel"_i18n);
cancelButton->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
cancelButton->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
cancelButton->Appearance.BorderInactive = ui::Colour(200, 200, 200);
@ -44,7 +44,7 @@ LocalSaveActivity::LocalSaveActivity(SaveFile save, OnSaved onSaved_) :
AddComponent(cancelButton);
SetCancelButton(cancelButton);
ui::Button * okayButton = new ui::Button(ui::Point(Size.X-76, Size.Y-16), ui::Point(76, 16), "Save");
ui::Button * okayButton = new ui::Button(ui::Point(Size.X-76, Size.Y-16), ui::Point(76, 16), "Save"_i18n);
okayButton->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
okayButton->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
okayButton->Appearance.TextInactive = style::Colour::InformationTitle;
@ -78,7 +78,7 @@ void LocalSaveActivity::Save()
{
if (filenameField->GetText().Contains('/') || filenameField->GetText().BeginsWith("."))
{
new ErrorMessage("Error", "Invalid filename.");
new ErrorMessage("Error"_i18n, "Invalid filename."_i18n);
}
else if (filenameField->GetText().length())
{
@ -87,7 +87,7 @@ void LocalSaveActivity::Save()
save.SetFileName(finalFilename);
if(Client::Ref().FileExists(finalFilename))
{
new ConfirmPrompt("Overwrite file", "Are you sure you wish to overwrite\n"+finalFilename.FromUtf8(), { [this, finalFilename] {
new ConfirmPrompt("Overwrite file"_i18n, "Are you sure you wish to overwrite\n"_i18n+finalFilename.FromUtf8(), { [this, finalFilename] {
saveWrite(finalFilename);
} });
}
@ -98,7 +98,7 @@ void LocalSaveActivity::Save()
}
else
{
new ErrorMessage("Error", "You must specify a filename.");
new ErrorMessage("Error"_i18n, "You must specify a filename."_i18n);
}
}
@ -115,9 +115,9 @@ void LocalSaveActivity::saveWrite(ByteString finalFilename)
gameSave->authors = localSaveInfo;
std::vector<char> saveData = gameSave->Serialise();
if (saveData.size() == 0)
new ErrorMessage("Error", "Unable to serialize game data.");
new ErrorMessage("Error"_i18n, "Unable to serialize game data."_i18n);
else if (Client::Ref().WriteFile(saveData, finalFilename))
new ErrorMessage("Error", "Unable to write save file.");
new ErrorMessage("Error"_i18n, "Unable to write save file."_i18n);
else
{
if (onSaved)

View File

@ -68,27 +68,27 @@ ServerSaveActivity::ServerSaveActivity(SaveInfo save, OnUploaded onUploaded_) :
AddComponent(titleLabel);
CheckName(save.GetName()); //set titleLabel text
ui::Label * previewLabel = new ui::Label(ui::Point((Size.X/2)+4, 5), ui::Point((Size.X/2)-8, 16), "Preview:");
ui::Label * previewLabel = new ui::Label(ui::Point((Size.X/2)+4, 5), ui::Point((Size.X/2)-8, 16), "Preview:"_i18n);
previewLabel->SetTextColour(style::Colour::InformationTitle);
previewLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
previewLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
AddComponent(previewLabel);
nameField = new ui::Textbox(ui::Point(8, 25), ui::Point((Size.X/2)-16, 16), save.GetName(), "[save name]");
nameField = new ui::Textbox(ui::Point(8, 25), ui::Point((Size.X/2)-16, 16), save.GetName(), "[save name]"_i18n);
nameField->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
nameField->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
nameField->SetActionCallback({ [this] { CheckName(nameField->GetText()); } });
AddComponent(nameField);
FocusComponent(nameField);
descriptionField = new ui::Textbox(ui::Point(8, 65), ui::Point((Size.X/2)-16, Size.Y-(65+16+4)), save.GetDescription(), "[save description]");
descriptionField = new ui::Textbox(ui::Point(8, 65), ui::Point((Size.X/2)-16, Size.Y-(65+16+4)), save.GetDescription(), "[save description]"_i18n);
descriptionField->SetMultiline(true);
descriptionField->SetLimit(254);
descriptionField->Appearance.VerticalAlign = ui::Appearance::AlignTop;
descriptionField->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
AddComponent(descriptionField);
publishedCheckbox = new ui::Checkbox(ui::Point(8, 45), ui::Point((Size.X/2)-80, 16), "Publish", "");
publishedCheckbox = new ui::Checkbox(ui::Point(8, 45), ui::Point((Size.X/2)-80, 16), "Publish"_i18n, "");
if(Client::Ref().GetAuthUser().Username != save.GetUserName())
{
//Save is not owned by the user, disable by default
@ -101,11 +101,11 @@ ServerSaveActivity::ServerSaveActivity(SaveInfo save, OnUploaded onUploaded_) :
}
AddComponent(publishedCheckbox);
pausedCheckbox = new ui::Checkbox(ui::Point(160, 45), ui::Point(55, 16), "Paused", "");
pausedCheckbox = new ui::Checkbox(ui::Point(160, 45), ui::Point(55, 16), "Paused"_i18n, "");
pausedCheckbox->SetChecked(save.GetGameSave()->paused);
AddComponent(pausedCheckbox);
ui::Button * cancelButton = new ui::Button(ui::Point(0, Size.Y-16), ui::Point((Size.X/2)-75, 16), "Cancel");
ui::Button * cancelButton = new ui::Button(ui::Point(0, Size.Y-16), ui::Point((Size.X/2)-75, 16), "Cancel"_i18n);
cancelButton->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
cancelButton->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
cancelButton->Appearance.BorderInactive = ui::Colour(200, 200, 200);
@ -115,7 +115,7 @@ ServerSaveActivity::ServerSaveActivity(SaveInfo save, OnUploaded onUploaded_) :
AddComponent(cancelButton);
SetCancelButton(cancelButton);
ui::Button * okayButton = new ui::Button(ui::Point((Size.X/2)-76, Size.Y-16), ui::Point(76, 16), "Save");
ui::Button * okayButton = new ui::Button(ui::Point((Size.X/2)-76, Size.Y-16), ui::Point(76, 16), "Save"_i18n);
okayButton->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
okayButton->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
okayButton->Appearance.TextInactive = style::Colour::InformationTitle;
@ -125,7 +125,7 @@ ServerSaveActivity::ServerSaveActivity(SaveInfo save, OnUploaded onUploaded_) :
AddComponent(okayButton);
SetOkayButton(okayButton);
ui::Button * PublishingInfoButton = new ui::Button(ui::Point((Size.X*3/4)-75, Size.Y-42), ui::Point(150, 16), "Publishing Info");
ui::Button * PublishingInfoButton = new ui::Button(ui::Point((Size.X*3/4)-75, Size.Y-42), ui::Point(150, 16), "Publishing Info"_i18n);
PublishingInfoButton->Appearance.HorizontalAlign = ui::Appearance::AlignCentre;
PublishingInfoButton->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
PublishingInfoButton->Appearance.TextInactive = style::Colour::InformationTitle;
@ -134,7 +134,7 @@ ServerSaveActivity::ServerSaveActivity(SaveInfo save, OnUploaded onUploaded_) :
} });
AddComponent(PublishingInfoButton);
ui::Button * RulesButton = new ui::Button(ui::Point((Size.X*3/4)-75, Size.Y-22), ui::Point(150, 16), "Save Uploading Rules");
ui::Button * RulesButton = new ui::Button(ui::Point((Size.X*3/4)-75, Size.Y-22), ui::Point(150, 16), "Save Uploading Rules"_i18n);
RulesButton->Appearance.HorizontalAlign = ui::Appearance::AlignCentre;
RulesButton->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
RulesButton->Appearance.TextInactive = style::Colour::InformationTitle;
@ -157,7 +157,7 @@ ServerSaveActivity::ServerSaveActivity(SaveInfo save, bool saveNow, OnUploaded o
onUploaded(onUploaded_),
saveUploadTask(NULL)
{
ui::Label * titleLabel = new ui::Label(ui::Point(0, 0), Size, "Saving to server...");
ui::Label * titleLabel = new ui::Label(ui::Point(0, 0), Size, "Saving to server..."_i18n);
titleLabel->SetTextColour(style::Colour::InformationTitle);
titleLabel->Appearance.HorizontalAlign = ui::Appearance::AlignCentre;
titleLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
@ -175,7 +175,7 @@ void ServerSaveActivity::NotifyDone(Task * task)
if(!task->GetSuccess())
{
Exit();
new ErrorMessage("Error", Client::Ref().GetLastError());
new ErrorMessage("Error"_i18n, Client::Ref().GetLastError());
}
else
{
@ -193,7 +193,8 @@ void ServerSaveActivity::Save()
{
if(Client::Ref().GetAuthUser().Username != save.GetUserName() && publishedCheckbox->GetChecked())
{
new ConfirmPrompt("Publish", "This save was created by " + save.GetUserName().FromUtf8() + ", you're about to publish this under your own name; If you haven't been given permission by the author to do so, please uncheck the publish box, otherwise continue", { [this] {
auto authorWarning = i18nMulti("This save was created by ", ", you're about to publish this under your own name; If you haven't been given permission by the author to do so, please uncheck the publish box, otherwise continue");
new ConfirmPrompt("Publish"_i18n, authorWarning[0] + save.GetUserName().FromUtf8() + authorWarning[1], { [this] {
Exit();
saveUpload();
} });
@ -206,7 +207,7 @@ void ServerSaveActivity::Save()
}
else
{
new ErrorMessage("Error", "You must specify a save name.");
new ErrorMessage("Error"_i18n, "You must specify a save name."_i18n);
}
}
@ -236,7 +237,7 @@ void ServerSaveActivity::saveUpload()
if(Client::Ref().UploadSave(save) != RequestOkay)
{
new ErrorMessage("Error", "Upload failed with error:\n"+Client::Ref().GetLastError());
new ErrorMessage("Error"_i18n, "Upload failed with error:\n"_i18n+Client::Ref().GetLastError());
}
else if (onUploaded)
{
@ -252,103 +253,20 @@ void ServerSaveActivity::Exit()
void ServerSaveActivity::ShowPublishingInfo()
{
String info =
"In The Powder Toy, one can save simulations to their account in two privacy levels: Published and unpublished. You can choose which one by checking or unchecking the 'publish' checkbox. Saves are unpublished by default, so if you do not check publish nobody will be able to see your saves.\n"
"\n"
"\btPublished saves\bw will appear on the 'By Date' feed and will be seen by many people. These saves also contribute to your Average Score, which is displayed publicly on your profile page on the website. Publish saves that you want people to see so they can comment and vote on.\n"
"\btUnpublished saves\bw will not be shown on the 'By Date' feed. These will not contribute to your Average Score. They are not completely private though, as anyone who knows the save id will be able to view it. You can give the save id out to show specific people the save but not allow just everyone to see it.\n"
"\n"
"To quickly resave a save, open it and click the left side of the split resave button to \bt'Reupload the current simulation'\bw. If you want to change the description or change the published status, you can click the right side to \bt'Modify simulation properties'\bw. Note that you can't change the name of saves; this will create an entirely new save with no comments, votes, or tags; separate from the original.\n"
"You may want to publish an unpublished save after it is finished, or to unpublish some currently published ones. You can do this by opening the save, selecting the 'Modify simulation properties' button, and changing the published status there. You can also \btunpublish or delete saves\bw by selecting them in the 'my own' section of the browser and clicking either one of the buttons that appear on bottom.\n"
"If a save is under a week old and gains popularity fast, it will be automatically placed on the \btfront page\bw. Only published saves will be able to get here. Moderators can also choose to promote any save onto the front page, but this happens rarely. They can also demote any save from the front page that breaks a rule or they feel doesn't belong.\n"
"Once you make a save, you can resave it as many times as you want. A short previous \btsave history\bw is saved, just right click any save in the save browser and select 'View History' to view it. This is useful for when you accidentally save something you didn't mean to and want to go back to the old version.\n"
;
new InformationMessage("Publishing Info", info, true);
new InformationMessage("Publishing Info"_i18n, currentLocale->GetSavePublishingInfo(), true);
}
void ServerSaveActivity::ShowRules()
{
String rules =
"\boSection S: Social and Community Rules\n"
"\bwThere are a few rules you should follow while interacting with the community. These rules are enforced by staff members and any issues related to violations of these rules may be brought to our attention by users. This section applies to saves uploaded, comments area, forums, and other areas of the community.\n"
"\n"
"\bt1. Try to use proper grammar.\bw English is the official community language, but use is not required in regional or cultural groups. If you cannot write English well, we advise that you use Google Translate.\n"
"\bt2. Do not spam.\bw There's not a one size fits all definition here, but the idea is usually obvious. In addition, the following are seen as spam and may be hidden or deleted:\n"
"- Posting multiple threads on the same subject. Try to combine threads on game feedback or suggestions into one thread.\n"
"- Bumping an old thread by replying. This is what we call 'necro' or 'necroing'. The content of the thread may be stale (fixing issues, ideas, etc). We recommend posting a new thread for an updated or more current response.\n"
"- Posting on a thread with '+1' or other short replies. There's no need to constantly bump a thread and make finding replies difficult. Replies are great for constructive feedback, while the '+1' button is to show your support for the content.\n"
"- Comments that are excessively long or gibberish. Making comments such as repeating the same letter or have little to no intended purpose, fall under this rule. Comments that are in a different language are exempt.\n"
"- Excessive formatting. UPPERCASE, Bold, and italics can be nice with moderate use, but please do not use them throughout the entire post.\n"
"\bt3. Keep swearing to a minimum.\bw Comments or saves containing swearing are at risk of being deleted. This also includes swearing in other languages.\n"
"\bt4. Refrain from uploading sexually explicit, offensive, or other inappropriate materials.\bw\n"
"- These include, but are not limited to: sex, drugs, racism, excessive politics, or anything that offends or insults a group of people.\n"
"- Reference to these topics in other languages is also prohibited. Do not attempt to bypass this rule.\n"
"- Posting URLs or images that violate this rule is prohibited. This includes links or text in your profile information.\n"
"\bt5. Do not advertise third-party games, sites, or other places not related to The Powder Toy.\bw\n"
"- Mainly this rule is intended to prevent people going through and advertising their own games and products.\n"
"- Unauthorized or unofficial community gathering places, such as Discord, are prohibited.\n"
"\bt6. Trolling is not allowed.\bw As with some rules, there's no clear definition. Users who repeatedly troll are far more likely to be banned and recieve longer bans than others.\n"
"\bt7. Do not impersonate anyone.\bw Registering accounts with names intentionally similar to other users in our community or other online communities is prohibited.\n"
"\bt8. Do not post about moderator decisions or issues.\bw If there is a problem regarding a ban on your account or content removal, please contact a moderator through the messages system. Otherwise, discussion about moderator actions should be avoided.\n"
"\bt9. Avoid backseat moderating.\bw Moderators are the ones who make the decisions. Users should refrain from threatening bans or possible results from breaking a rule. If there is a possible issue or you are unsure, we recommend reporting the issue through the 'Report' button or via the messaging system on the website.\n"
"\bt10. Condoning of breaking common laws is prohibited.\bw The jurisdiction of which country's laws applies is not clear, but there are some common ones to know. These include, but not limited to:\n"
"- Piracy of software, music, bagels, etc.\n"
"- Hacking / Stealing accounts\n"
"- Theft / Fraud\n"
"\bt11. Do not stalk or harass any user.\bw This has been a growing problem in recent years by different methods, but generally these include:\n"
"- 'Doxing' user(s) to find where they live or their real identity\n"
"- Constantly messaging a user when they wish to refrain from any contact\n"
"- Mass downvoting saves\n"
"- Posting rude or unnecessary comments on someone's content (saves, forum threads, etc)\n"
"- Coercing a group of users to 'target' a user\n"
"- Personal arguments or hatred. This could be arguing in the comments or making hate saves\n"
"- Discrimination, in general, of people. This could be religious, ethnic, etc.\n"
"\n"
"\boSection G: In-Game Rules\n"
"\bwThis section of the rules is focused on in-game actions. Though, Section S also applies in-game, the following rules are more specialized to in-game community interaction.\n"
"\bt1. Don't claim other people's work.\bw This could be simply re-uploading another user's or utilizing large sections of saves. Derivative works are allowed, with proper usage. Should you utilize someone's work, by default you must credit the author. Unless the author has explicitly noted different usage terms, this is the standard policy. Derivative works are characterized by innovative usage and originality percentage (ie. how much is original versus someone's work?). Stolen saves will be unpublished or disabled.\n"
"\bt2. Self-voting or vote fraud is not allowed.\bw This is defined as making multiple accounts to vote on your own saves or the saves of others. We enforce this rule strictly, therefore, you must understand that there are very few successful ban appeals. Please ensure you and other accounts are not voting from the same household. All alternate accounts will be permanently banned, the main account will be temporarily banned and any affected saves will be disabaled.\n"
"\bt3. Asking for votes of any kind is frowned upon.\bw Saves which do this will be unpublished until the issue is fixed. Examples of such that are under this rules are:\n"
"- Signs that may hint at voting up or down. The signature green arrow or asking for votes goes under this rule.\n"
"- Gimmicks that ask for votes. These might be a total number of votes in exchange for something, like '100 votes and I'll make a better version'. This is what we define as vote farming. Any type of vote farming is not allowed.\n"
"- Asking for votes in return for usage of a save or for any other reason is prohibited.\n"
"\bt4. Do not spam.\bw As mentioned earlier, there are no standards for what counts as spam. Here are some examples that may qualify as spamming:\n"
"- Uploading or re-uploading similar saves within a short amount of time. Don't try to circumvent the system to have your saves seen/voted by people. This includes uploading 'junk' or 'blank' saves with little to no purpose. These saves will be unpublished.\n"
"- Uploading text-only saves. These may be announcements or looking for help of sorts. We have the forums and comments area available for many purposes these text-only saves would serve. These saves will be removed from front page.\n"
"- Uploading art saves is not strictly prohibited, but may result in a front-page demotion. We like to see usage of the variety of elements in a creative manner. Lack of these factors (such as in deco-only saves) will typically result in a front-page demotion\n"
"\bt5. Refrain from uploading sexually explicit or other inappropriate materials. These saves will be deleted and will lead to a ban.\bw\n"
"- These include, but are not limited to: sex, drugs, racism, excessive politics, or anything that offends or insults a group of people.\n"
"- Don't try to circumvent this rule. Anything that intentionally refers to these concepts/ideas by direct or indirect means falls under this rule.\n"
"- Reference to these topics in other languages is also prohibited. Do not attempt to bypass this rule.\n"
"- Posting URLs or images that violate this rule is prohibited. This includes links or text in your profile information.\n"
"\bt6. Image plotting is strictly prohibited.\bw This includes usage of scripting or any third-party tools to plot or create a save for you. Saves using CGI will be deleted and you may receive a ban.\n"
"\bt7. Keep logos and signs to a minimum.\bw These saves may be removed from front page. Items that this rule restricts are:\n"
"- Excessive logos placed\n"
"- Signs without intended purpose\n"
"- Fake update or notifications signs\n"
"- Linking other saves that have no related purposes\n"
"\bt8. Do not place offtopic or inappropriate tags.\bw Tags are only there to improve search results. They should generally only be one word descriptions of the save. Sentences or subjective tags may be deleted. Inappropriate or offensive tags will likely get you banned.\n"
"\bt9. Intentional lag inducing or crashing saves are prohibited.\bw If the majority of users are writing about the save causing crashes or lag, then the save will fall under this rule. These saves will be removed from front page or disabled.\n"
"\bt10. Do not misuse the reporting system.\bw Sending in report reasons such as 'bad save' or gibberish wastes our time. Unless the issue pertains to a possible rule violation or community issue, please refrain from sending a report. If you think the save violates or poses a community issue, send a report anyway! Bans will never happen if you are reporting a save in good faith.\n"
"\bt11. Do not ask for saves to be demoted or removed from the front-page.\bw Unless the save violates any rules, it will stay on the front-page. There is no exception to this rule for art saves, please do not report art either.\n"
"\n"
"\boSection R: Other\n"
"\bwModerators may interpret these rules as they see fit. Not all rules are equal, some are enforced less than others. Moderators make the final decision on what is and isn't against the rules, but we have made our best effort here to cover all unwanted behavior here. Notice will be posted in this thread whenever the rules are updated.\n"
"\n"
"Violation of these rules may result in removal of posts / comments, unpublishing or disabling saves, removing saves from front page, or in more extreme cases, a temporary or permanent ban. There are various manual and automated measures in place to enforce these rules. The severity and resulting decisions may not be consistent between moderators.\n"
"\n"
"If you have any questions about what is and isn't against the rules, feel free to contact a moderator.";
new InformationMessage("Save Uploading Rules", rules, true);
new InformationMessage("Save Uploading Rules"_i18n, currentLocale->GetRules(), true);
}
void ServerSaveActivity::CheckName(String newname)
{
if (newname.length() && newname == save.GetName() && save.GetUserName() == Client::Ref().GetAuthUser().Username)
titleLabel->SetText("Modify simulation properties:");
titleLabel->SetText("Modify simulation properties:"_i18n);
else
titleLabel->SetText("Upload new simulation:");
titleLabel->SetText("Upload new simulation:"_i18n);
}
void ServerSaveActivity::OnTick(float dt)

View File

@ -219,12 +219,9 @@ void SearchController::ClearSelection()
void SearchController::RemoveSelected()
{
StringBuilder desc;
desc << "Are you sure you want to delete " << searchModel->GetSelected().size() << " save";
if(searchModel->GetSelected().size()>1)
desc << "s";
desc << "?";
new ConfirmPrompt("Delete saves", desc.Build(), { [this] {
auto deleteConfirm = i18nMulti("Are you sure you want to delete ", "?");
size_t count = searchModel->GetSelected().size();
new ConfirmPrompt("Delete saves"_i18n, String::Build(deleteConfirm[0], count, ' ', i18nPlural("save", count), deleteConfirm[1]), { [this] {
removeSelectedC();
} });
}
@ -241,10 +238,12 @@ void SearchController::removeSelectedC()
{
for (size_t i = 0; i < saves.size(); i++)
{
notifyStatus(String::Build("Deleting save [", saves[i], "] ..."));
auto deleting = i18nMulti("Deleting save [", "] ...");
notifyStatus(String::Build(deleting[0], saves[i], deleting[1]));
if (Client::Ref().DeleteSave(saves[i])!=RequestOkay)
{
notifyError(String::Build("Failed to delete [", saves[i], "]: ", Client::Ref().GetLastError()));
auto failed = i18nMulti("Failed to delete [", "]: ");
notifyError(String::Build(failed[0], saves[i], failed[1], Client::Ref().GetLastError()));
c->Refresh();
return false;
}
@ -256,19 +255,16 @@ void SearchController::removeSelectedC()
};
std::vector<int> selected = searchModel->GetSelected();
new TaskWindow("Removing saves", new RemoveSavesTask(selected, this));
new TaskWindow("Removing saves"_i18n, new RemoveSavesTask(selected, this));
ClearSelection();
searchModel->UpdateSaveList(searchModel->GetPageNum(), searchModel->GetLastQuery());
}
void SearchController::UnpublishSelected(bool publish)
{
StringBuilder desc;
desc << "Are you sure you want to " << (publish ? String("publish ") : String("unpublish ")) << searchModel->GetSelected().size() << " save";
if (searchModel->GetSelected().size() > 1)
desc << "s";
desc << "?";
new ConfirmPrompt(publish ? String("Publish Saves") : String("Unpublish Saves"), desc.Build(), { [this, publish] {
auto publishConfirm = publish ? i18nMulti("Are you sure you want to publish ", "?") : i18nMulti("Are you sure you want to unpublish ", "?");
size_t count = searchModel->GetSelected().size();
new ConfirmPrompt(publish ? "Publish Saves"_i18n : "Unpublish Saves"_i18n, String::Build(publishConfirm[0], count, ' ', i18nPlural("save", count), publishConfirm[1]), { [this, publish] {
unpublishSelectedC(publish);
} });
}
@ -285,7 +281,8 @@ void SearchController::unpublishSelectedC(bool publish)
bool PublishSave(int saveID)
{
notifyStatus(String::Build("Publishing save [", saveID, "]"));
auto publishing = i18nMulti("Publishing save [", "]");
notifyStatus(String::Build(publishing[0], saveID, publishing[1]));
if (Client::Ref().PublishSave(saveID) != RequestOkay)
return false;
return true;
@ -293,7 +290,8 @@ void SearchController::unpublishSelectedC(bool publish)
bool UnpublishSave(int saveID)
{
notifyStatus(String::Build("Unpublishing save [", saveID, "]"));
auto unpublishing = i18nMulti("Unpublishing save [", "]");
notifyStatus(String::Build(unpublishing[0], saveID, unpublishing[1]));
if (Client::Ref().UnpublishSave(saveID) != RequestOkay)
return false;
return true;
@ -311,9 +309,15 @@ void SearchController::unpublishSelectedC(bool publish)
if (!ret)
{
if (publish) // uses html page so error message will be spam
notifyError(String::Build("Failed to publish [", saves[i], "], is this save yours?"));
{
auto failed = i18nMulti("Failed to publish [", "], is this save yours?");
notifyError(String::Build(failed[0], saves[i], failed[1]));
}
else
notifyError(String::Build("Failed to unpublish [", saves[i], "]: " + Client::Ref().GetLastError()));
{
auto failed = i18nMulti("Failed to unpublish [", "]: ");
notifyError(String::Build(failed[0], saves[i], failed[1], Client::Ref().GetLastError()));
}
c->Refresh();
return false;
}
@ -325,7 +329,7 @@ void SearchController::unpublishSelectedC(bool publish)
};
std::vector<int> selected = searchModel->GetSelected();
new TaskWindow(publish ? String("Publishing Saves") : String("Unpublishing Saves"), new UnpublishSavesTask(selected, this, publish));
new TaskWindow(publish ? "Publishing Saves"_i18n : "Unpublishing Saves"_i18n, new UnpublishSavesTask(selected, this, publish));
}
void SearchController::FavouriteSelected()
@ -339,10 +343,12 @@ void SearchController::FavouriteSelected()
{
for (size_t i = 0; i < saves.size(); i++)
{
notifyStatus(String::Build("Favouring save [", saves[i], "]"));
auto favouring = i18nMulti("Favouring save [", "]");
notifyStatus(String::Build(favouring[0], saves[i], favouring[1]));
if (Client::Ref().FavouriteSave(saves[i], true)!=RequestOkay)
{
notifyError(String::Build("Failed to favourite [", saves[i], "]: " + Client::Ref().GetLastError()));
auto failed = i18nMulti("Failed to favourite [", "]: ");
notifyError(String::Build(failed[0], saves[i], failed[1], Client::Ref().GetLastError()));
return false;
}
notifyProgress((float(i+1)/float(saves.size())*100));
@ -360,10 +366,12 @@ void SearchController::FavouriteSelected()
{
for (size_t i = 0; i < saves.size(); i++)
{
notifyStatus(String::Build("Unfavouring save [", saves[i], "]"));
auto unfavouring = i18nMulti("Unfavouring save [", "]");
notifyStatus(String::Build(unfavouring[0], saves[i], unfavouring[1]));
if (Client::Ref().FavouriteSave(saves[i], false)!=RequestOkay)
{
notifyError(String::Build("Failed to unfavourite [", saves[i], "]: " + Client::Ref().GetLastError()));
auto failed = i18nMulti("Failed to unfavourite [", "]: ");
notifyError(String::Build(failed[0], saves[i], failed[1], Client::Ref().GetLastError()));
return false;
}
notifyProgress((float(i+1)/float(saves.size())*100));
@ -374,8 +382,8 @@ void SearchController::FavouriteSelected()
std::vector<int> selected = searchModel->GetSelected();
if (!searchModel->GetShowFavourite())
new TaskWindow("Favouring saves", new FavouriteSavesTask(selected));
new TaskWindow("Favouring saves"_i18n, new FavouriteSavesTask(selected));
else
new TaskWindow("Unfavouring saves", new UnfavouriteSavesTask(selected));
new TaskWindow("Unfavouring saves"_i18n, new UnfavouriteSavesTask(selected));
ClearSelection();
}

View File

@ -148,7 +148,7 @@ void SearchModel::Update()
if(!saveList.size())
{
lastError = Client::Ref().GetLastError();
if (lastError == "Unspecified Error")
if (lastError == "Unspecified Error"_i18n)
lastError = "";
}

View File

@ -36,9 +36,9 @@ SearchView::SearchView():
Client::Ref().AddListener(this);
nextButton = new ui::Button(ui::Point(WINDOWW-52, WINDOWH-18), ui::Point(50, 16), String("Next ") + 0xE015);
previousButton = new ui::Button(ui::Point(2, WINDOWH-18), ui::Point(50, 16), 0xE016 + String(" Prev"));
tagsLabel = new ui::Label(ui::Point(270, WINDOWH-18), ui::Point(WINDOWW-540, 16), "\boPopular Tags:");
nextButton = new ui::Button(ui::Point(WINDOWW-52, WINDOWH-18), ui::Point(50, 16), "Next "_i18n + 0xE015);
previousButton = new ui::Button(ui::Point(2, WINDOWH-18), ui::Point(50, 16), 0xE016 + " Prev"_i18n);
tagsLabel = new ui::Label(ui::Point(270, WINDOWH-18), ui::Point(WINDOWW-540, 16), "\boPopular Tags:"_i18n);
try
{
motdLabel = new ui::RichLabel(ui::Point(51, WINDOWH-18), ui::Point(WINDOWW-102, 16), Client::Ref().GetMessageOfTheDay());
@ -48,7 +48,8 @@ SearchView::SearchView():
pageTextbox = new ui::Textbox(ui::Point(283, WINDOWH-18), ui::Point(41, 16), "");
pageTextbox->SetActionCallback({ [this] { textChanged(); } });
pageTextbox->SetInputType(ui::Textbox::Number);
pageLabel = new ui::Label(ui::Point(0, WINDOWH-18), ui::Point(30, 16), "Page"); //page [TEXTBOX] of y
auto pageOf = i18nMulti("Page", "of "); //page [TEXTBOX] of y
pageLabel = new ui::Label(ui::Point(0, WINDOWH-18), ui::Point(30, 16), pageOf[0]);
pageLabel->Appearance.HorizontalAlign = ui::Appearance::AlignRight;
pageCountLabel = new ui::Label(ui::Point(WINDOWW/2+6, WINDOWH-18), ui::Point(50, 16), "");
pageCountLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
@ -56,14 +57,14 @@ SearchView::SearchView():
AddComponent(pageCountLabel);
AddComponent(pageTextbox);
searchField = new ui::Textbox(ui::Point(60, 10), ui::Point(WINDOWW-238, 17), "", "[search]");
searchField = new ui::Textbox(ui::Point(60, 10), ui::Point(WINDOWW-238, 17), "", "[search]"_i18n);
searchField->Appearance.icon = IconSearch;
searchField->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
searchField->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
searchField->SetActionCallback({ [this] { doSearch(); } });
FocusComponent(searchField);
sortButton = new ui::Button(ui::Point(WINDOWW-140, 10), ui::Point(61, 17), "Sort");
sortButton = new ui::Button(ui::Point(WINDOWW-140, 10), ui::Point(61, 17), "Sort"_i18n);
sortButton->SetIcon(IconVoteSort);
sortButton->SetTogglable(true);
sortButton->SetActionCallback({ [this] { c->ChangeSort(); } });
@ -71,7 +72,7 @@ SearchView::SearchView():
sortButton->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
AddComponent(sortButton);
ownButton = new ui::Button(ui::Point(WINDOWW-70, 10), ui::Point(61, 17), "My Own");
ownButton = new ui::Button(ui::Point(WINDOWW-70, 10), ui::Point(61, 17), "My Own"_i18n);
ownButton->SetIcon(IconMyOwn);
ownButton->SetTogglable(true);
ownButton->SetActionCallback({ [this] { c->ShowOwn(ownButton->GetToggleState()); } });
@ -114,27 +115,27 @@ SearchView::SearchView():
loadingSpinner = new ui::Spinner(ui::Point((WINDOWW/2)-12, (WINDOWH/2)+12), ui::Point(24, 24));
AddComponent(loadingSpinner);
ui::Label * searchPrompt = new ui::Label(ui::Point(10, 10), ui::Point(50, 16), "Search:");
ui::Label * searchPrompt = new ui::Label(ui::Point(10, 10), ui::Point(50, 16), "Search:"_i18n);
searchPrompt->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
searchPrompt->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
AddComponent(searchPrompt);
removeSelected = new ui::Button(ui::Point(((WINDOWW-415)/2), WINDOWH-18), ui::Point(100, 16), "Delete");
removeSelected = new ui::Button(ui::Point(((WINDOWW-415)/2), WINDOWH-18), ui::Point(100, 16), "Delete"_i18n);
removeSelected->Visible = false;
removeSelected->SetActionCallback({ [this] { c->RemoveSelected(); } });
AddComponent(removeSelected);
unpublishSelected = new ui::Button(ui::Point(((WINDOWW-415)/2)+105, WINDOWH-18), ui::Point(100, 16), "Unpublish");
unpublishSelected = new ui::Button(ui::Point(((WINDOWW-415)/2)+105, WINDOWH-18), ui::Point(100, 16), "Unpublish"_i18n);
unpublishSelected->Visible = false;
unpublishSelected->SetActionCallback({ [this] { c->UnpublishSelected(publishButtonShown); } });
AddComponent(unpublishSelected);
favouriteSelected = new ui::Button(ui::Point(((WINDOWW-415)/2)+210, WINDOWH-18), ui::Point(100, 16), "Favourite");
favouriteSelected = new ui::Button(ui::Point(((WINDOWW-415)/2)+210, WINDOWH-18), ui::Point(100, 16), "Favourite"_i18n);
favouriteSelected->Visible = false;
favouriteSelected->SetActionCallback({ [this] { c->FavouriteSelected(); } });
AddComponent(favouriteSelected);
clearSelection = new ui::Button(ui::Point(((WINDOWW-415)/2)+315, WINDOWH-18), ui::Point(100, 16), "Clear selection");
clearSelection = new ui::Button(ui::Point(((WINDOWW-415)/2)+315, WINDOWH-18), ui::Point(100, 16), "Clear selection"_i18n);
clearSelection->Visible = false;
clearSelection->SetActionCallback({ [this] { c->ClearSelection(); } });
AddComponent(clearSelection);
@ -173,10 +174,8 @@ void SearchView::clearSearch()
void SearchView::textChanged()
{
int num = pageTextbox->GetText().ToNumber<int>(true);
if (num < 0) //0 is allowed so that you can backspace the 1
pageTextbox->SetText("1");
else if (num > pageCount)
pageTextbox->SetText(String::Build(pageCount));
if(num < 0 || num > pageCount) //0 is allowed so that you can backspace the 1
pageTextbox->SetText(String::Build(num < 0 ? 1 : pageCount));
changed = true;
lastChanged = GetTicks()+600;
}
@ -219,13 +218,13 @@ void SearchView::NotifySortChanged(SearchModel * sender)
if(sender->GetSort() == "best")
{
sortButton->SetToggleState(false);
sortButton->SetText("By votes");
sortButton->SetText("By votes"_i18n);
sortButton->SetIcon(IconVoteSort);
}
else
{
sortButton->SetToggleState(true);
sortButton->SetText("By date");
sortButton->SetText("By date"_i18n);
sortButton->SetIcon(IconDateSort);
}
}
@ -274,7 +273,8 @@ void SearchView::NotifyPageChanged(SearchModel * sender)
}
else
{
String pageInfo = String::Build("of ", pageCount);
auto pageof = i18nMulti("Page", "of ");
String pageInfo = String::Build(pageof[1], pageCount);
pageCountLabel->SetText(pageInfo);
int width = Graphics::textwidth(pageInfo);
@ -465,9 +465,9 @@ void SearchView::NotifySaveListChanged(SearchModel * sender)
//string messageOfTheDay = sender->GetMessageOfTheDay();
if(sender->GetShowFavourite())
favouriteSelected->SetText("Unfavourite");
favouriteSelected->SetText("Unfavourite"_i18n);
else
favouriteSelected->SetText("Favourite");
favouriteSelected->SetText("Favourite"_i18n);
for (size_t i = 0; i < saveButtons.size(); i++)
{
@ -502,12 +502,12 @@ void SearchView::NotifySaveListChanged(SearchModel * sender)
loadingSpinner->Visible = false;
if (!errorLabel)
{
errorLabel = new ui::Label(ui::Point((WINDOWW/2)-100, (WINDOWH/2)-6), ui::Point(200, 12), "Error");
errorLabel = new ui::Label(ui::Point((WINDOWW/2)-100, (WINDOWH/2)-6), ui::Point(200, 12), "Error"_i18n);
AddComponent(errorLabel);
}
if (!sender->GetSavesLoaded())
{
errorLabel->SetText("Loading...");
errorLabel->SetText("Loading..."_i18n);
loadingSpinner->Visible = true;
}
else
@ -515,7 +515,7 @@ void SearchView::NotifySaveListChanged(SearchModel * sender)
if(sender->GetLastError().length())
errorLabel->SetText("\bo" + sender->GetLastError());
else
errorLabel->SetText("\boNo saves found");
errorLabel->SetText("\boNo saves found"_i18n);
}
}
else
@ -612,12 +612,12 @@ void SearchView::NotifySelectedChanged(SearchModel * sender)
pageCountLabel->Visible = false;
if (published <= selected.size()/2)
{
unpublishSelected->SetText("Publish");
unpublishSelected->SetText("Publish"_i18n);
publishButtonShown = true;
}
else
{
unpublishSelected->SetText("Unpublish");
unpublishSelected->SetText("Unpublish"_i18n);
publishButtonShown = false;
}
}

View File

@ -18,20 +18,20 @@
TagsView::TagsView():
ui::Window(ui::Point(-1, -1), ui::Point(195, 250))
{
closeButton = new ui::Button(ui::Point(0, Size.Y-16), ui::Point(195, 16), "Close");
closeButton = new ui::Button(ui::Point(0, Size.Y-16), ui::Point(195, 16), "Close"_i18n);
closeButton->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
closeButton->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
closeButton->SetActionCallback({ [this] { c->Exit(); } });
AddComponent(closeButton);
SetCancelButton(closeButton);
tagInput = new ui::Textbox(ui::Point(8, Size.Y-40), ui::Point(Size.X-60, 16), "", "[new tag]");
tagInput = new ui::Textbox(ui::Point(8, Size.Y-40), ui::Point(Size.X-60, 16), "", "[new tag]"_i18n);
tagInput->Appearance.icon = IconTag;
tagInput->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
tagInput->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
AddComponent(tagInput);
addButton = new ui::Button(ui::Point(tagInput->Position.X+tagInput->Size.X+4, tagInput->Position.Y), ui::Point(40, 16), "Add");
addButton = new ui::Button(ui::Point(tagInput->Position.X+tagInput->Size.X+4, tagInput->Position.Y), ui::Point(40, 16), "Add"_i18n);
addButton->Appearance.icon = IconAdd;
addButton->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
addButton->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
@ -41,7 +41,7 @@ TagsView::TagsView():
if (!Client::Ref().GetAuthUser().UserID)
addButton->Enabled = false;
title = new ui::Label(ui::Point(5, 5), ui::Point(185, 28), "Manage tags: \bgTags are only to \nbe used to improve search results");
title = new ui::Label(ui::Point(5, 5), ui::Point(185, 28), "Manage tags: \bgTags are only to \nbe used to improve search results"_i18n);
title->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
title->Appearance.VerticalAlign = ui::Appearance::AlignTop;
title->SetMultiline(true);
@ -90,7 +90,7 @@ void TagsView::NotifyTagsChanged(TagsModel * sender)
}
catch(TagsModelException & ex)
{
new ErrorMessage("Could not remove tag", ByteString(ex.what()).FromUtf8());
new ErrorMessage("Could not remove tag"_i18n, ByteString(ex.what()).FromUtf8());
}
} });
tags.push_back(tempButton);
@ -121,7 +121,7 @@ void TagsView::addTag()
{
if (tagInput->GetText().length() < 4)
{
new ErrorMessage("Tag not long enough", "Must be at least 4 letters");
new ErrorMessage("Tag not long enough"_i18n, "Must be at least 4 letters"_i18n);
return;
}
try
@ -130,7 +130,7 @@ void TagsView::addTag()
}
catch(TagsModelException & ex)
{
new ErrorMessage("Could not add tag", ByteString(ex.what()).FromUtf8());
new ErrorMessage("Could not add tag"_i18n, ByteString(ex.what()).FromUtf8());
}
tagInput->SetText("");
}

View File

@ -34,7 +34,7 @@ private:
String error;
http::Request *request = new http::Request(updateName);
request->Start();
notifyStatus("Downloading update");
notifyStatus("Downloading update"_i18n);
notifyProgress(-1);
while(!request->CheckDone())
{
@ -48,30 +48,31 @@ private:
ByteString data = request->Finish(&status);
if (status!=200)
{
error = String::Build("Server responded with Status ", status);
notifyError("Could not download update: " + error);
error = String::Build("Server responded with Status "_i18n, status);
notifyError("Could not download update: "_i18n + error);
return false;
}
if (!data.size())
{
error = "Server responded with nothing";
notifyError("Server did not return any data");
error = "Server responded with nothing"_i18n;
notifyError("Server did not return any data"_i18n);
return false;
}
notifyStatus("Unpacking update");
notifyStatus("Unpacking update"_i18n);
notifyProgress(-1);
unsigned int uncompressedLength;
if(data.size()<16)
{
error = String::Build("Unsufficient data, got ", data.size(), " bytes");
auto errMsg = i18nMulti("Insufficient data, got ", " bytes");
error = String::Build(errMsg[0], data.size(), errMsg[1]);
goto corrupt;
}
if (data[0]!=0x42 || data[1]!=0x75 || data[2]!=0x54 || data[3]!=0x54)
{
error = "Invalid update format";
error = "Invalid update format"_i18n;
goto corrupt;
}
@ -84,7 +85,8 @@ private:
res = (char *)malloc(uncompressedLength);
if (!res)
{
error = String::Build("Unable to allocate ", uncompressedLength, " bytes of memory for decompression");
auto errMsg = i18nMulti("Unable to allocate ", " bytes of memory for decompression");
error = String::Build(errMsg[0], uncompressedLength, errMsg[1]);
goto corrupt;
}
@ -92,12 +94,12 @@ private:
dstate = BZ2_bzBuffToBuffDecompress((char *)res, (unsigned *)&uncompressedLength, &data[8], data.size()-8, 0, 0);
if (dstate)
{
error = String::Build("Unable to decompress update: ", dstate);
error = String::Build("Unable to decompress update: "_i18n, dstate);
free(res);
goto corrupt;
}
notifyStatus("Applying update");
notifyStatus("Applying update"_i18n);
notifyProgress(-1);
Client::Ref().SetPref("version.update", true);
@ -106,14 +108,14 @@ private:
{
Client::Ref().SetPref("version.update", false);
update_cleanup();
notifyError("Update failed - try downloading a new version.");
notifyError("Update failed - try downloading a new version."_i18n);
return false;
}
return true;
corrupt:
notifyError("Downloaded update is corrupted\n" + error);
notifyError("Downloaded update is corrupted\n"_i18n + error);
return false;
}
};
@ -126,7 +128,7 @@ UpdateActivity::UpdateActivity() {
file = ByteString::Build(SCHEME, SERVER, Client::Ref().GetUpdateInfo().File);
#endif
updateDownloadTask = new UpdateDownloadTask(file, this);
updateWindow = new TaskWindow("Downloading update...", updateDownloadTask, true);
updateWindow = new TaskWindow("Downloading update..."_i18n, updateDownloadTask, true);
}
void UpdateActivity::NotifyDone(Task * sender)
@ -147,11 +149,11 @@ void UpdateActivity::Exit()
void UpdateActivity::NotifyError(Task * sender)
{
#ifdef UPDATESERVER
# define FIRST_LINE "Please go online to manually download a newer version.\n"
# define FIRST_LINE "Please go online to manually download a newer version.\n"_i18n
#else
# define FIRST_LINE "Please visit the website to download a newer version.\n"
# define FIRST_LINE "Please visit the website to download a newer version.\n"_i18n
#endif
new ConfirmPrompt("Autoupdate failed", FIRST_LINE "Error: " + sender->GetError(), { [this] {
new ConfirmPrompt("Autoupdate failed"_i18n, FIRST_LINE + "Error: "_i18n + sender->GetError(), { [this] {
#ifndef UPDATESERVER
Platform::OpenURI(SCHEME "powdertoy.co.uk/Download.html");
#endif

View File

@ -22,7 +22,7 @@ CommandInterface::CommandInterface(GameController * c, GameModel * m) {
int CommandInterface::Command(String command)
{
lastError = "No interpreter";
lastError = "No interpreter"_i18n;
return -1;
}

View File

@ -280,16 +280,16 @@ void luacon_hook(lua_State * l, lua_Debug * ar)
{
if(ar->event == LUA_HOOKCOUNT && Platform::GetTime()-ui::Engine::Ref().LastTick() > 3000)
{
if(ConfirmPrompt::Blocking("Script not responding", "The Lua script may have stopped responding. There might be an infinite loop. Press \"Stop\" to stop it", "Stop"))
if(ConfirmPrompt::Blocking("Script not responding"_i18n, "The Lua script may have stopped responding. There might be an infinite loop. Press \"Stop\" to stop it"_i18n, "Stop"_i18n))
luaL_error(l, "Error: Script not responding");
ui::Engine::Ref().LastTick(Platform::GetTime());
}
}
String luacon_geterror()
ByteString luacon_geterror()
{
luaL_tostring(luacon_ci->l, -1);
String err = ByteString(luaL_optstring(luacon_ci->l, -1, "failed to execute")).FromUtf8();
ByteString err = luaL_optstring(luacon_ci->l, -1, "failed to execute");
lua_pop(luacon_ci->l, 1);
return err;
}
@ -331,7 +331,7 @@ int luacon_elementReplacement(UPDATE_FUNC_ARGS)
lua_pushinteger(luacon_ci->l, nt);
callret = lua_pcall(luacon_ci->l, 5, 1, 0);
if (callret)
luacon_ci->Log(CommandInterface::LogError, luacon_geterror());
luacon_ci->Log(CommandInterface::LogError, luacon_geterror().FromUtf8());
if(lua_isboolean(luacon_ci->l, -1)){
retval = lua_toboolean(luacon_ci->l, -1);
}
@ -391,7 +391,7 @@ int luacon_graphicsReplacement(GRAPHICS_FUNC_ARGS, int i)
callret = lua_pcall(luacon_ci->l, 4, 10, 0);
if (callret)
{
luacon_ci->Log(CommandInterface::LogError, luacon_geterror());
luacon_ci->Log(CommandInterface::LogError, luacon_geterror().FromUtf8());
lua_pop(luacon_ci->l, 1);
}
else
@ -459,7 +459,7 @@ int luatpt_graphics_func(lua_State *l)
int luatpt_error(lua_State* l)
{
String errorMessage = ByteString(luaL_optstring(l, 1, "Error text")).FromUtf8();
ErrorMessage::Blocking("Error", errorMessage);
ErrorMessage::Blocking("Error"_i18n, errorMessage);
return 0;
}
@ -1386,7 +1386,7 @@ int luatpt_getscript(lua_State* l)
int confirmPrompt = luaL_optint(l, 4, 1);
ByteString url = ByteString::Build(SCHEME "starcatcher.us/scripts/main.lua?get=", scriptID);
if (confirmPrompt && !ConfirmPrompt::Blocking("Do you want to install script?", url.FromUtf8(), "Install"))
if (confirmPrompt && !ConfirmPrompt::Blocking("Do you want to install script?"_i18n, url.FromUtf8(), "Install"_i18n))
return 0;
int ret;
@ -1410,7 +1410,7 @@ int luatpt_getscript(lua_State* l)
{
fclose(outputfile);
outputfile = NULL;
if (!confirmPrompt || ConfirmPrompt::Blocking("File already exists, overwrite?", ByteString(filename).FromUtf8(), "Overwrite"))
if (!confirmPrompt || ConfirmPrompt::Blocking("File already exists, overwrite?"_i18n, ByteString(filename).FromUtf8(), "Overwrite"_i18n))
{
outputfile = fopen(filename, "wb");
}

View File

@ -205,7 +205,7 @@ bool LuaEvents::HandleEvent(LuaScriptInterface *luacon_ci, Event *event, ByteStr
int callret = lua_pcall(l, numArgs, 1, 0);
if (callret)
{
if (luacon_geterror(luacon_ci) == "Error: Script not responding")
if (luacon_geterror(luacon_ci) == "Error: Script not responding"_i18n) // probably not a good idea
{
ui::Engine::Ref().LastTick(Platform::GetTime());
for (int j = i; j <= len - 1; j++)

View File

@ -37,7 +37,7 @@ extern LuaSmartRef *tptPart;
void luaopen_eventcompat(lua_State *l);
void luacon_hook(lua_State *L, lua_Debug *ar);
int luacon_eval(const char *command);
String luacon_geterror();
ByteString luacon_geterror();
void luacon_close();
void initLegacyProps();
int luacon_partsread(lua_State* l);

View File

@ -370,9 +370,9 @@ void LuaScriptInterface::Init()
{
lua_State *l = luacon_ci->l;
if(luaL_loadfile(l, "autorun.lua") || lua_pcall(l, 0, 0, 0))
luacon_ci->Log(CommandInterface::LogError, luacon_geterror());
luacon_ci->Log(CommandInterface::LogError, luacon_geterror().FromUtf8());
else
luacon_ci->Log(CommandInterface::LogWarning, "Loaded autorun.lua");
luacon_ci->Log(CommandInterface::LogWarning, "Loaded autorun.lua"_i18n);
}
}
@ -2703,7 +2703,7 @@ void luaCreateWrapper(ELEMENT_CREATE_FUNC_ARGS)
lua_pushinteger(luacon_ci->l, v);
if (lua_pcall(luacon_ci->l, 5, 0, 0))
{
luacon_ci->Log(CommandInterface::LogError, "In create func: " + luacon_geterror());
luacon_ci->Log(CommandInterface::LogError, "In create func: " + luacon_geterror().FromUtf8());
lua_pop(luacon_ci->l, 1);
}
}
@ -2721,7 +2721,7 @@ bool luaCreateAllowedWrapper(ELEMENT_CREATE_ALLOWED_FUNC_ARGS)
lua_pushinteger(luacon_ci->l, t);
if (lua_pcall(luacon_ci->l, 4, 1, 0))
{
luacon_ci->Log(CommandInterface::LogError, "In create allowed: " + luacon_geterror());
luacon_ci->Log(CommandInterface::LogError, "In create allowed: " + luacon_geterror().FromUtf8());
lua_pop(luacon_ci->l, 1);
}
else
@ -2746,7 +2746,7 @@ void luaChangeTypeWrapper(ELEMENT_CHANGETYPE_FUNC_ARGS)
lua_pushinteger(luacon_ci->l, to);
if (lua_pcall(luacon_ci->l, 5, 0, 0))
{
luacon_ci->Log(CommandInterface::LogError, "In change type: " + luacon_geterror());
luacon_ci->Log(CommandInterface::LogError, "In change type: " + luacon_geterror().FromUtf8());
lua_pop(luacon_ci->l, 1);
}
}
@ -2763,7 +2763,7 @@ static bool luaCtypeDrawWrapper(CTYPEDRAW_FUNC_ARGS)
lua_pushinteger(luacon_ci->l, v);
if (lua_pcall(luacon_ci->l, 3, 1, 0))
{
luacon_ci->Log(CommandInterface::LogError, luacon_geterror());
luacon_ci->Log(CommandInterface::LogError, luacon_geterror().FromUtf8());
lua_pop(luacon_ci->l, 1);
}
else
@ -3941,8 +3941,8 @@ int LuaScriptInterface::Command(String command)
}
if (lua_type(l, -1) != LUA_TFUNCTION)
{
lastError = luacon_geterror();
String err = lastError;
ByteString err = luacon_geterror();
lastError = err.FromUtf8();
if (err.Contains("near '<eof>'")) //the idea stolen from lua-5.1.5/lua.c
lastError = "...";
else
@ -3953,7 +3953,7 @@ int LuaScriptInterface::Command(String command)
lastCode = "";
ret = lua_pcall(l, 0, LUA_MULTRET, 0);
if (ret)
lastError = luacon_geterror();
lastError = luacon_geterror().FromUtf8();
else
{
for (level++;level<=lua_gettop(l);level++)
@ -4003,7 +4003,7 @@ String highlight(String command)
{
StringBuilder result;
int pos = 0;
String::value_type const*raw = command.c_str();
String::value_type const *raw = command.c_str();
String::value_type c;
while ((c = raw[pos]))
{
@ -4011,7 +4011,7 @@ String highlight(String command)
{
int len = 0;
String::value_type w;
String::value_type const* wstart = raw+pos;
String::value_type const *wstart = raw + pos;
while((w = wstart[len]) && ((w >= 'A' && w <= 'Z') || (w >= 'a' && w <= 'z') || (w >= '0' && w <= '9') || w == '_'))
len++;
#define CMP(X) (String(wstart, len) == X)
@ -4030,7 +4030,7 @@ String highlight(String command)
{
int len = 2;
String::value_type w;
String::value_type const* wstart = raw+pos;
String::value_type const *wstart = raw + pos;
while((w = wstart[len]) && ((w >= '0' && w <= '9') || (w >= 'A' && w <= 'F') || (w >= 'a' && w <= 'f')))
len++;
result << "\x0F\xD3\x36\x82" << String(wstart, len) << "\bw";
@ -4040,7 +4040,7 @@ String highlight(String command)
{
int len = 0;
String::value_type w;
String::value_type const* wstart = raw+pos;
String::value_type const *wstart = raw + pos;
bool seendot = false;
while((w = wstart[len]) && ((w >= '0' && w <= '9') || w == '.'))
{
@ -4072,7 +4072,7 @@ String highlight(String command)
{
int len = 1, eqs=0;
String::value_type w;
String::value_type const* wstart = raw + pos;
String::value_type const *wstart = raw + pos;
while((w = wstart[len]) && (w == '='))
{
eqs++;
@ -4083,12 +4083,12 @@ String highlight(String command)
if(w == ']')
{
int nlen = 1;
String::value_type const* cstart = wstart + len;
String::value_type const *cstart = wstart + len;
while((w = cstart[nlen]) && (w == '='))
nlen++;
if(w == ']' && nlen == eqs+1)
if(w == ']' && nlen == eqs + 1)
{
len += nlen+1;
len += nlen + 1;
break;
}
}
@ -4101,7 +4101,7 @@ String highlight(String command)
{
int len = 1;
String::value_type w;
String::value_type const* wstart = raw+pos;
String::value_type const *wstart = raw + pos;
while((w = wstart[len]) && (w != c))
{
if(w == '\\' && wstart[len + 1])
@ -4120,7 +4120,7 @@ String highlight(String command)
{
int len = 3, eqs = 0;
String::value_type w;
String::value_type const* wstart = raw + pos;
String::value_type const *wstart = raw + pos;
while((w = wstart[len]) && (w == '='))
{
eqs++;
@ -4131,12 +4131,12 @@ String highlight(String command)
if(w == ']')
{
int nlen = 1;
String::value_type const* cstart = wstart + len;
String::value_type const *cstart = wstart + len;
while((w = cstart[nlen]) && (w == '='))
nlen++;
if(w == ']' && nlen == eqs + 1)
{
len += nlen+1;
len += nlen + 1;
break;
}
}
@ -4149,7 +4149,7 @@ String highlight(String command)
{
int len = 2;
String::value_type w;
String::value_type const* wstart = raw + pos;
String::value_type const *wstart = raw + pos;
while((w = wstart[len]) && (w != '\n'))
len++;
result << "\x0F\x85\x99\x01" << String(wstart, len) << "\bw";
@ -4179,7 +4179,7 @@ String LuaScriptInterface::FormatCommand(String command)
{
if(command.size() && command[0] == '!')
{
return "!"+legacy->FormatCommand(command.Substr(1));
return "!" + legacy->FormatCommand(command.Substr(1));
}
else
return highlight(command);

View File

@ -54,7 +54,7 @@ AnyType::operator StringType()
else if (type == TypePoint && value.pt)
{
ui::Point thisPoint = *(value.pt);
return StringType(String::Build(thisPoint.X, ",", thisPoint.Y));
return StringType(String::Build(thisPoint.X, ',', thisPoint.Y));
}
else
throw InvalidConversionException(type, TypeString);

View File

@ -84,9 +84,10 @@ public:
class InvalidConversionException: public GeneralException
{
static std::array<String, 2> getErrorMsg() { return i18nMulti("Invalid conversion from ", " to "); }
public:
InvalidConversionException(ValueType from_, ValueType to_):
GeneralException("Invalid conversion from " + AnyType::TypeName(from_).FromAscii() + " to " + AnyType::TypeName(to_).FromAscii()) {
GeneralException(getErrorMsg()[0] + AnyType::TypeName(from_).FromAscii() + getErrorMsg()[1] + AnyType::TypeName(to_).FromAscii()) {
}
};

View File

@ -266,7 +266,7 @@ AnyType TPTScriptInterface::tptS_set(std::deque<String> * words)
FormatType propertyFormat;
int propertyOffset = GetPropertyOffset(property.Value().ToUtf8(), propertyFormat);
if (propertyOffset == -1)
throw GeneralException("Invalid property");
throw GeneralException("Invalid property"_i18n);
//Selector
int newValue = 0;
@ -289,7 +289,7 @@ AnyType TPTScriptInterface::tptS_set(std::deque<String> * words)
else if (newString.at(newString.length()-1) == 'F')
newValuef = (atof(newString.SubstrFromEnd(1).ToUtf8().c_str())-32.0f)*5/9+273.15f;
else
throw GeneralException("Invalid value for assignment");
throw GeneralException("Invalid value for assignment"_i18n);
}
else
{
@ -298,15 +298,15 @@ AnyType TPTScriptInterface::tptS_set(std::deque<String> * words)
{
// TODO: add element CAKE to invalidate this
if (!strcasecmp(((StringType)value).Value().ToUtf8().c_str(),"cake"))
throw GeneralException("Cake is a lie, not an element");
throw GeneralException("Invalid element");
throw GeneralException("Cake is a lie, not an element"_i18n);
throw GeneralException("Invalid element"_i18n);
}
}
}
else
throw GeneralException("Invalid value for assignment");
throw GeneralException("Invalid value for assignment"_i18n);
if (property.Value() == "type" && (newValue < 0 || newValue >= PT_NUM || !sim->elements[newValue].Enabled))
throw GeneralException("Invalid element");
throw GeneralException("Invalid element"_i18n);
if (selector.GetType() == TypePoint || selector.GetType() == TypeNumber)
{
@ -315,13 +315,13 @@ AnyType TPTScriptInterface::tptS_set(std::deque<String> * words)
{
ui::Point tempPoint = ((PointType)selector).Value();
if(tempPoint.X<0 || tempPoint.Y<0 || tempPoint.Y >= YRES || tempPoint.X >= XRES)
throw GeneralException("Invalid position");
throw GeneralException("Invalid position"_i18n);
}
else
partIndex = ((NumberType)selector).Value();
if(partIndex<0 || partIndex>NPART || sim->parts[partIndex].type==0)
throw GeneralException("Invalid particle");
throw GeneralException("Invalid particle"_i18n);
switch(propertyFormat)
{
@ -386,9 +386,9 @@ AnyType TPTScriptInterface::tptS_set(std::deque<String> * words)
type = m->GetSimulation()->GetParticleType(((StringType)selector).Value().ToUtf8());
if (type<0 || type>=PT_NUM)
throw GeneralException("Invalid particle type");
throw GeneralException("Invalid particle type"_i18n);
if (type==0)
throw GeneralException("Cannot set properties of particles that do not exist");
throw GeneralException("Cannot set properties of particles that do not exist"_i18n);
switch(propertyFormat)
{
case FormatInt:
@ -426,7 +426,7 @@ AnyType TPTScriptInterface::tptS_set(std::deque<String> * words)
}
}
else
throw GeneralException("Invalid selector");
throw GeneralException("Invalid selector"_i18n);
return NumberType(returnValue);
}
@ -444,14 +444,14 @@ AnyType TPTScriptInterface::tptS_create(std::deque<String> * words)
else if(createType.GetType() == TypeString)
type = m->GetSimulation()->GetParticleType(((StringType)createType).Value().ToUtf8());
else
throw GeneralException("Invalid type");
throw GeneralException("Invalid type"_i18n);
if(type == -1)
throw GeneralException("Invalid particle type");
throw GeneralException("Invalid particle type"_i18n);
ui::Point tempPoint = position.Value();
if(tempPoint.X<0 || tempPoint.Y<0 || tempPoint.Y >= YRES || tempPoint.X >= XRES)
throw GeneralException("Invalid position");
throw GeneralException("Invalid position"_i18n);
int v = -1;
if (ID(type))
@ -475,18 +475,18 @@ AnyType TPTScriptInterface::tptS_delete(std::deque<String> * words)
{
ui::Point deletePoint = ((PointType)partRef).Value();
if(deletePoint.X<0 || deletePoint.Y<0 || deletePoint.Y >= YRES || deletePoint.X >= XRES)
throw GeneralException("Invalid position");
throw GeneralException("Invalid position"_i18n);
sim->delete_part(deletePoint.X, deletePoint.Y);
}
else if(partRef.GetType() == TypeNumber)
{
int partIndex = ((NumberType)partRef).Value();
if(partIndex < 0 || partIndex >= NPART)
throw GeneralException("Invalid particle index");
throw GeneralException("Invalid particle index"_i18n);
sim->kill_part(partIndex);
}
else
throw GeneralException("Invalid particle reference");
throw GeneralException("Invalid particle reference"_i18n);
return NumberType(0);
}
@ -502,7 +502,7 @@ AnyType TPTScriptInterface::tptS_load(std::deque<String> * words)
return NumberType(0);
}
else
throw GeneralException("Invalid save ID");
throw GeneralException("Invalid save ID"_i18n);
}
AnyType TPTScriptInterface::tptS_bubble(std::deque<String> * words)
@ -512,7 +512,7 @@ AnyType TPTScriptInterface::tptS_bubble(std::deque<String> * words)
ui::Point bubblePos = bubblePosA.Value();
if(bubblePos.X<0 || bubblePos.Y<0 || bubblePos.Y >= YRES || bubblePos.X >= XRES)
throw GeneralException("Invalid position");
throw GeneralException("Invalid position"_i18n);
Simulation * sim = m->GetSimulation();
@ -581,7 +581,7 @@ AnyType TPTScriptInterface::tptS_reset(std::deque<String> * words)
}
else
{
throw GeneralException("Unknown reset command");
throw GeneralException("Unknown reset command"_i18n);
}
return NumberType(0);

View File

@ -29,7 +29,7 @@ Element::Element():
Weight(50),
HeatConduct(128),
Description("No description"),
Description("No description"_i18n),
Properties(TYPE_SOLID),

View File

@ -79,13 +79,13 @@ String sign::getDisplayText(Simulation *sim, int &x0, int &y0, int &w, int &h, b
}
else if (between_curlies == "type")
{
formatted_text << (part ? sim->BasicParticleInfo(*part) : (formatted_text.Size() ? String::Build("empty") : String::Build("Empty")));
formatted_text << (part ? sim->BasicParticleInfo(*part) : (formatted_text.Size() ? "empty"_i18n : "Empty"_i18n));
if (v95)
*v95 = true;
}
else if (between_curlies == "ctype")
{
formatted_text << (part ? ((part->ctype && sim->IsValidElement(part->ctype)) ? sim->ElementResolve(part->ctype, -1) : String::Build(part->ctype)) : (formatted_text.Size() ? String::Build("empty") : String::Build("Empty")));
formatted_text << (part ? ((part->ctype && sim->IsValidElement(part->ctype)) ? sim->ElementResolve(part->ctype, -1) : String::Build(part->ctype)) : (formatted_text.Size() ? "empty"_i18n : "Empty"_i18n));
if (v95)
*v95 = true;
}

View File

@ -13,6 +13,6 @@ SimTool::SimTool():
Identifier("DEFAULT_TOOL_INVALID"),
Name(""),
Colour(PIXPACK(0xFFFFFF)),
Description("NULL Tool, does NOTHING")
Description("NULL Tool, does NOTHING"_i18n)
{
}

View File

@ -5219,7 +5219,7 @@ String Simulation::ElementResolve(int type, int ctype)
{
return elements[type].Name;
}
return "Empty";
return "Empty"_i18n;
}
String Simulation::BasicParticleInfo(Particle const &sample_part)
@ -5230,17 +5230,17 @@ String Simulation::BasicParticleInfo(Particle const &sample_part)
int pavg1int = (int)sample_part.pavg[1];
if (type == PT_LAVA && ctype && IsValidElement(ctype))
{
sampleInfo << "Molten " << ElementResolve(ctype, -1);
sampleInfo << "Molten "_i18n << ElementResolve(ctype, -1);
}
else if ((type == PT_PIPE || type == PT_PPIP) && ctype && IsValidElement(ctype))
{
if (ctype == PT_LAVA && pavg1int && IsValidElement(pavg1int))
{
sampleInfo << ElementResolve(type, -1) << " with molten " << ElementResolve(pavg1int, -1);
sampleInfo << ElementResolve(type, -1) << " with molten "_i18n << ElementResolve(pavg1int, -1);
}
else
{
sampleInfo << ElementResolve(type, -1) << " with " << ElementResolve(ctype, pavg1int);
sampleInfo << ElementResolve(type, -1) << " with "_i18n << ElementResolve(ctype, pavg1int);
}
}
else

View File

@ -14,30 +14,30 @@ std::vector<gol_menu> LoadGOLMenu()
{
return
std::vector<gol_menu>{
{"GOL", PIXPACK(0x0CAC00), 0, String("Game Of Life: Begin 3/Stay 23")},
{"HLIF", PIXPACK(0xFF0000), 1, String("High Life: B36/S23")},
{"ASIM", PIXPACK(0x0000FF), 2, String("Assimilation: B345/S4567")},
{"2x2", PIXPACK(0xFFFF00), 3, String("2x2: B36/S125")},
{"DANI", PIXPACK(0x00FFFF), 4, String("Day and Night: B3678/S34678")},
{"AMOE", PIXPACK(0xFF00FF), 5, String("Amoeba: B357/S1358")},
{"MOVE", PIXPACK(0xFFFFFF), 6, String("'Move' particles. Does not move things.. it is a life type: B368/S245")},
{"PGOL", PIXPACK(0xE05010), 7, String("Pseudo Life: B357/S238")},
{"DMOE", PIXPACK(0x500000), 8, String("Diamoeba: B35678/S5678")},
{"34", PIXPACK(0x500050), 9, String("34: B34/S34")},
{"LLIF", PIXPACK(0x505050), 10, String("Long Life: B345/S5")},
{"STAN", PIXPACK(0x5000FF), 11, String("Stains: B3678/S235678")},
{"SEED", PIXPACK(0xFBEC7D), 12, String("Seeds: B2/S")},
{"MAZE", PIXPACK(0xA8E4A0), 13, String("Maze: B3/S12345")},
{"COAG", PIXPACK(0x9ACD32), 14, String("Coagulations: B378/S235678")},
{"WALL", PIXPACK(0x0047AB), 15, String("Walled cities: B45678/S2345")},
{"GNAR", PIXPACK(0xE5B73B), 16, String("Gnarl: B1/S1")},
{"REPL", PIXPACK(0x259588), 17, String("Replicator: B1357/S1357")},
{"MYST", PIXPACK(0x0C3C00), 18, String("Mystery: B3458/S05678")},
{"LOTE", PIXPACK(0xFF0000), 19, String("Living on the Edge: B37/S3458/4")},
{"FRG2", PIXPACK(0x00FF00), 20, String("Like Frogs rule: B3/S124/3")},
{"STAR", PIXPACK(0x0000FF), 21, String("Like Star Wars rule: B278/S3456/6")},
{"FROG", PIXPACK(0x00AA00), 22, String("Frogs: B34/S12/3")},
{"BRAN", PIXPACK(0xCCCC00), 23, String("Brian 6: B246/S6/3")}
{"GOL", PIXPACK(0x0CAC00), 0, "Game Of Life: Begin 3/Stay 23"_i18n},
{"HLIF", PIXPACK(0xFF0000), 1, "High Life: B36/S23"_i18n},
{"ASIM", PIXPACK(0x0000FF), 2, "Assimilation: B345/S4567"_i18n},
{"2x2", PIXPACK(0xFFFF00), 3, "2x2: B36/S125"_i18n},
{"DANI", PIXPACK(0x00FFFF), 4, "Day and Night: B3678/S34678"_i18n},
{"AMOE", PIXPACK(0xFF00FF), 5, "Amoeba: B357/S1358"_i18n},
{"MOVE", PIXPACK(0xFFFFFF), 6, "'Move' particles. Does not move things.. it is a life type: B368/S245"_i18n},
{"PGOL", PIXPACK(0xE05010), 7, "Pseudo Life: B357/S238"_i18n},
{"DMOE", PIXPACK(0x500000), 8, "Diamoeba: B35678/S5678"_i18n},
{"34", PIXPACK(0x500050), 9, "34: B34/S34"_i18n},
{"LLIF", PIXPACK(0x505050), 10, "Long Life: B345/S5"_i18n},
{"STAN", PIXPACK(0x5000FF), 11, "Stains: B3678/S235678"_i18n},
{"SEED", PIXPACK(0xFBEC7D), 12, "Seeds: B2/S"_i18n},
{"MAZE", PIXPACK(0xA8E4A0), 13, "Maze: B3/S12345"_i18n},
{"COAG", PIXPACK(0x9ACD32), 14, "Coagulations: B378/S235678"_i18n},
{"WALL", PIXPACK(0x0047AB), 15, "Walled cities: B45678/S2345"_i18n},
{"GNAR", PIXPACK(0xE5B73B), 16, "Gnarl: B1/S1"_i18n},
{"REPL", PIXPACK(0x259588), 17, "Replicator: B1357/S1357"_i18n},
{"MYST", PIXPACK(0x0C3C00), 18, "Mystery: B3458/S05678"_i18n},
{"LOTE", PIXPACK(0xFF0000), 19, "Living on the Edge: B37/S3458/4"_i18n},
{"FRG2", PIXPACK(0x00FF00), 20, "Like Frogs rule: B3/S124/3"_i18n},
{"STAR", PIXPACK(0x0000FF), 21, "Like Star Wars rule: B278/S3456/6"_i18n},
{"FROG", PIXPACK(0x00AA00), 22, "Frogs: B34/S12/3"_i18n},
{"BRAN", PIXPACK(0xCCCC00), 23, "Brian 6: B246/S6/3"_i18n}
};
}
@ -109,25 +109,25 @@ std::vector<wall_type> LoadWalls()
{
return
std::vector<wall_type>{
{PIXPACK(0x808080), PIXPACK(0x000000), 0, Renderer::WallIcon, String("ERASE"), "DEFAULT_WL_ERASE", String("Erases walls.")},
{PIXPACK(0xC0C0C0), PIXPACK(0x101010), 0, Renderer::WallIcon, String("CONDUCTIVE WALL"), "DEFAULT_WL_CNDTW", String("Blocks everything. Conductive.")},
{PIXPACK(0x808080), PIXPACK(0x808080), 0, Renderer::WallIcon, String("EWALL"), "DEFAULT_WL_EWALL", String("E-Wall. Becomes transparent when electricity is connected.")},
{PIXPACK(0xFF8080), PIXPACK(0xFF2008), 1, Renderer::WallIcon, String("DETECTOR"), "DEFAULT_WL_DTECT", String("Detector. Generates electricity when a particle is inside.")},
{PIXPACK(0x808080), PIXPACK(0x000000), 0, Renderer::WallIcon, String("STREAMLINE"), "DEFAULT_WL_STRM", String("Streamline. Set start point of a streamline.")},
{PIXPACK(0x8080FF), PIXPACK(0x000000), 1, Renderer::WallIcon, String("FAN"), "DEFAULT_WL_FAN", String("Fan. Accelerates air. Use the line tool to set direction and strength.")},
{PIXPACK(0xC0C0C0), PIXPACK(0x101010), 2, Renderer::WallIcon, String("LIQUID WALL"), "DEFAULT_WL_LIQD", String("Allows liquids, blocks all other particles. Conductive.")},
{PIXPACK(0x808080), PIXPACK(0x000000), 1, Renderer::WallIcon, String("ABSORB WALL"), "DEFAULT_WL_ABSRB", String("Absorbs particles but lets air currents through.")},
{PIXPACK(0x808080), PIXPACK(0x000000), 3, Renderer::WallIcon, String("WALL"), "DEFAULT_WL_WALL", String("Basic wall, blocks everything.")},
{PIXPACK(0x3C3C3C), PIXPACK(0x000000), 1, Renderer::WallIcon, String("AIRONLY WALL"), "DEFAULT_WL_AIR", String("Allows air, but blocks all particles.")},
{PIXPACK(0x575757), PIXPACK(0x000000), 1, Renderer::WallIcon, String("POWDER WALL"), "DEFAULT_WL_POWDR", String("Allows powders, blocks all other particles.")},
{PIXPACK(0xFFFF22), PIXPACK(0x101010), 2, Renderer::WallIcon, String("CONDUCTOR"), "DEFAULT_WL_CNDTR", String("Conductor. Allows all particles to pass through and conducts electricity.")},
{PIXPACK(0x242424), PIXPACK(0x101010), 0, Renderer::WallIcon, String("EHOLE"), "DEFAULT_WL_EHOLE", String("E-Hole. absorbs particles, releases them when powered.")},
{PIXPACK(0x579777), PIXPACK(0x000000), 1, Renderer::WallIcon, String("GAS WALL"), "DEFAULT_WL_GAS", String("Allows gases, blocks all other particles.")},
{PIXPACK(0xFFEE00), PIXPACK(0xAA9900), 4, Renderer::WallIcon, String("GRAVITY WALL"), "DEFAULT_WL_GRVTY", String("Gravity wall. Newtonian Gravity has no effect inside a box drawn with this.")},
{PIXPACK(0xFFAA00), PIXPACK(0xAA5500), 4, Renderer::WallIcon, String("ENERGY WALL"), "DEFAULT_WL_ENRGY", String("Allows energy particles, blocks all other particles.")},
{PIXPACK(0xDCDCDC), PIXPACK(0x000000), 1, Renderer::WallIcon, String("AIRBLOCK WALL"), "DEFAULT_WL_NOAIR", String("Allows all particles, but blocks air.")},
{PIXPACK(0x808080), PIXPACK(0x000000), 0, Renderer::WallIcon, String("ERASEALL"), "DEFAULT_WL_ERASEA", String("Erases walls, particles, and signs.")},
{PIXPACK(0x800080), PIXPACK(0x000000), 0, Renderer::WallIcon, String("STASIS WALL"), "DEFAULT_WL_STASIS", String("Freezes particles inside the wall in place until powered.")},
{PIXPACK(0x808080), PIXPACK(0x000000), 0, Renderer::WallIcon, "ERASE", "DEFAULT_WL_ERASE", "Erases walls."_i18n},
{PIXPACK(0xC0C0C0), PIXPACK(0x101010), 0, Renderer::WallIcon, "CONDUCTIVE WALL", "DEFAULT_WL_CNDTW", "Blocks everything. Conductive."_i18n},
{PIXPACK(0x808080), PIXPACK(0x808080), 0, Renderer::WallIcon, "EWALL", "DEFAULT_WL_EWALL", "E-Wall. Becomes transparent when electricity is connected."_i18n},
{PIXPACK(0xFF8080), PIXPACK(0xFF2008), 1, Renderer::WallIcon, "DETECTOR", "DEFAULT_WL_DTECT", "Detector. Generates electricity when a particle is inside."_i18n},
{PIXPACK(0x808080), PIXPACK(0x000000), 0, Renderer::WallIcon, "STREAMLINE", "DEFAULT_WL_STRM", "Streamline. Set start point of a streamline."_i18n},
{PIXPACK(0x8080FF), PIXPACK(0x000000), 1, Renderer::WallIcon, "FAN", "DEFAULT_WL_FAN", "Fan. Accelerates air. Use the line tool to set direction and strength."_i18n},
{PIXPACK(0xC0C0C0), PIXPACK(0x101010), 2, Renderer::WallIcon, "LIQUID WALL", "DEFAULT_WL_LIQD", "Allows liquids, blocks all other particles. Conductive."_i18n},
{PIXPACK(0x808080), PIXPACK(0x000000), 1, Renderer::WallIcon, "ABSORB WALL", "DEFAULT_WL_ABSRB", "Absorbs particles but lets air currents through."_i18n},
{PIXPACK(0x808080), PIXPACK(0x000000), 3, Renderer::WallIcon, "WALL", "DEFAULT_WL_WALL", "Basic wall, blocks everything."_i18n},
{PIXPACK(0x3C3C3C), PIXPACK(0x000000), 1, Renderer::WallIcon, "AIRONLY WALL", "DEFAULT_WL_AIR", "Allows air, but blocks all particles."_i18n},
{PIXPACK(0x575757), PIXPACK(0x000000), 1, Renderer::WallIcon, "POWDER WALL", "DEFAULT_WL_POWDR", "Allows powders, blocks all other particles."_i18n},
{PIXPACK(0xFFFF22), PIXPACK(0x101010), 2, Renderer::WallIcon, "CONDUCTOR", "DEFAULT_WL_CNDTR", "Conductor. Allows all particles to pass through and conducts electricity."_i18n},
{PIXPACK(0x242424), PIXPACK(0x101010), 0, Renderer::WallIcon, "EHOLE", "DEFAULT_WL_EHOLE", "E-Hole. absorbs particles, releases them when powered."_i18n},
{PIXPACK(0x579777), PIXPACK(0x000000), 1, Renderer::WallIcon, "GAS WALL", "DEFAULT_WL_GAS", "Allows gases, blocks all other particles."_i18n},
{PIXPACK(0xFFEE00), PIXPACK(0xAA9900), 4, Renderer::WallIcon, "GRAVITY WALL", "DEFAULT_WL_GRVTY", "Gravity wall. Newtonian Gravity has no effect inside a box drawn with this."_i18n},
{PIXPACK(0xFFAA00), PIXPACK(0xAA5500), 4, Renderer::WallIcon, "ENERGY WALL", "DEFAULT_WL_ENRGY", "Allows energy particles, blocks all other particles."_i18n},
{PIXPACK(0xDCDCDC), PIXPACK(0x000000), 1, Renderer::WallIcon, "AIRBLOCK WALL", "DEFAULT_WL_NOAIR", "Allows all particles, but blocks air."_i18n},
{PIXPACK(0x808080), PIXPACK(0x000000), 0, Renderer::WallIcon, "ERASEALL", "DEFAULT_WL_ERASEA", "Erases walls, particles, and signs."_i18n},
{PIXPACK(0x800080), PIXPACK(0x000000), 0, Renderer::WallIcon, "STASIS WALL", "DEFAULT_WL_STASIS", "Freezes particles inside the wall in place until powered."_i18n},
};
}
@ -135,24 +135,24 @@ std::vector<menu_section> LoadMenus()
{
return
std::vector<menu_section>{
{0xE041, String("Walls"), 0, 1},
{0xE042, String("Electronics"), 0, 1},
{0xE056, String("Powered Materials"), 0, 1},
{0xE019, String("Sensors"), 0, 1},
{0xE062, String("Force"), 0, 1},
{0xE043, String("Explosives"), 0, 1},
{0xE045, String("Gases"), 0, 1},
{0xE044, String("Liquids"), 0, 1},
{0xE050, String("Powders"), 0, 1},
{0xE051, String("Solids"), 0, 1},
{0xE046, String("Radioactive"), 0, 1},
{0xE04C, String("Special"), 0, 1},
{0xE052, String("Game Of Life"), 0, 1},
{0xE057, String("Tools"), 0, 1},
{0xE067, String("Favorites"), 0, 1},
{0xE064, String("Decoration tools"), 0, 1},
{0xE048, String("Cracker"), 0, 0},
{0xE048, String("Cracker!"), 0, 0},
{0xE041, "Walls"_i18n, 0, 1},
{0xE042, "Electronics"_i18n, 0, 1},
{0xE056, "Powered Materials"_i18n, 0, 1},
{0xE019, "Sensors"_i18n, 0, 1},
{0xE062, "Force"_i18n, 0, 1},
{0xE043, "Explosives"_i18n, 0, 1},
{0xE045, "Gases"_i18n, 0, 1},
{0xE044, "Liquids"_i18n, 0, 1},
{0xE050, "Powders"_i18n, 0, 1},
{0xE051, "Solids"_i18n, 0, 1},
{0xE046, "Radioactive"_i18n, 0, 1},
{0xE04C, "Special"_i18n, 0, 1},
{0xE052, "Game Of Life"_i18n, 0, 1},
{0xE057, "Tools"_i18n, 0, 1},
{0xE067, "Favorites"_i18n, 0, 1},
{0xE064, "Decoration tools"_i18n, 0, 1},
{0xE048, "Cracker"_i18n, 0, 0},
{0xE048, "Cracker!"_i18n, 0, 0},
};
}

View File

@ -30,7 +30,7 @@ void Element::Element_ACEL()
Weight = 100;
HeatConduct = 251;
Description = "Accelerator, speeds up nearby elements.";
Description = "Accelerator, speeds up nearby elements."_i18n;
Properties = TYPE_SOLID;

View File

@ -31,7 +31,7 @@ void Element::Element_ACID()
Weight = 10;
HeatConduct = 34;
Description = "Dissolves almost everything.";
Description = "Dissolves almost everything."_i18n;
Properties = TYPE_LIQUID|PROP_DEADLY;

View File

@ -30,7 +30,7 @@ void Element::Element_AMTR()
Weight = 100;
HeatConduct = 70;
Description = "Anti-Matter, destroys a majority of particles.";
Description = "Anti-Matter, destroys a majority of particles."_i18n;
Properties = TYPE_GAS;

View File

@ -30,7 +30,7 @@ void Element::Element_ANAR()
Weight = 85;
HeatConduct = 70;
Description = "Anti-air. Very light dust, which behaves opposite gravity.";
Description = "Anti-air. Very light dust, which behaves opposite gravity."_i18n;
Properties = TYPE_PART;

View File

@ -29,7 +29,7 @@ void Element::Element_ARAY()
Weight = 100;
HeatConduct = 0;
Description = "Ray Emitter. Rays create points when they collide.";
Description = "Ray Emitter. Rays create points when they collide."_i18n;
Properties = TYPE_SOLID|PROP_LIFE_DEC;

View File

@ -29,7 +29,7 @@ void Element::Element_BANG()
Weight = 100;
HeatConduct = 88;
Description = "TNT, explodes all at once.";
Description = "TNT, explodes all at once."_i18n;
Properties = TYPE_SOLID | PROP_NEUTPENETRATE;

View File

@ -29,7 +29,7 @@ void Element::Element_BCLN()
Weight = 100;
HeatConduct = 251;
Description = "Breakable Clone.";
Description = "Breakable Clone."_i18n;
Properties = TYPE_SOLID | PROP_LIFE_DEC | PROP_LIFE_KILL_DEC | PROP_NOCTYPEDRAW;

View File

@ -31,7 +31,7 @@ void Element::Element_BCOL()
Weight = 90;
HeatConduct = 150;
Description = "Broken Coal. Heavy particles, burns slowly.";
Description = "Broken Coal. Heavy particles, burns slowly."_i18n;
Properties = TYPE_PART;

View File

@ -27,7 +27,7 @@ void Element::Element_BGLA()
Weight = 90;
HeatConduct = 150;
Description = "Broken Glass, heavy particles formed when glass breaks under pressure. Meltable. Bagels.";
Description = "Broken Glass, heavy particles formed when glass breaks under pressure. Meltable. Bagels."_i18n;
Properties = TYPE_PART | PROP_HOT_GLOW;

View File

@ -28,7 +28,7 @@ void Element::Element_BHOL()
DefaultProperties.temp = R_TEMP + 70.0f + 273.15f;
HeatConduct = 255;
Description = "Vacuum, sucks in other particles and heats up.";
Description = "Vacuum, sucks in other particles and heats up."_i18n;
Properties = TYPE_SOLID;

View File

@ -30,7 +30,7 @@ void Element::Element_BIZR()
Weight = 30;
HeatConduct = 29;
Description = "Bizarre... contradicts the normal state changes. Paints other elements with its deco color.";
Description = "Bizarre... contradicts the normal state changes. Paints other elements with its deco color."_i18n;
Properties = TYPE_LIQUID;

View File

@ -31,7 +31,7 @@ void Element::Element_BIZRG()
DefaultProperties.temp = R_TEMP - 200.0f + 273.15f;
HeatConduct = 42;
Description = "Bizarre gas.";
Description = "Bizarre gas."_i18n;
Properties = TYPE_GAS;

View File

@ -31,7 +31,7 @@ void Element::Element_BIZRS()
DefaultProperties.temp = R_TEMP + 300.0f + 273.15f;
HeatConduct = 251;
Description = "Bizarre solid.";
Description = "Bizarre solid."_i18n;
Properties = TYPE_SOLID;

View File

@ -29,7 +29,7 @@ void Element::Element_BMTL()
Weight = 100;
HeatConduct = 251;
Description = "Breakable metal. Common conductive building material, can melt and break under pressure.";
Description = "Breakable metal. Common conductive building material, can melt and break under pressure."_i18n;
Properties = TYPE_SOLID|PROP_CONDUCTS|PROP_LIFE_DEC|PROP_HOT_GLOW;

View File

@ -31,7 +31,7 @@ void Element::Element_BOMB()
DefaultProperties.temp = R_TEMP - 2.0f + 273.15f;
HeatConduct = 29;
Description = "Bomb. Explodes and destroys all surrounding particles when it touches something.";
Description = "Bomb. Explodes and destroys all surrounding particles when it touches something."_i18n;
Properties = TYPE_PART|PROP_SPARKSETTLE;

View File

@ -30,7 +30,7 @@ void Element::Element_BOYL()
DefaultProperties.temp = R_TEMP + 2.0f + 273.15f;
HeatConduct = 42;
Description = "Boyle, variable pressure gas. Expands when heated.";
Description = "Boyle, variable pressure gas. Expands when heated."_i18n;
Properties = TYPE_GAS;

View File

@ -29,7 +29,7 @@ void Element::Element_BRAY()
Weight = 100;
HeatConduct = 251;
Description = "Ray Point. Rays create points when they collide.";
Description = "Ray Point. Rays create points when they collide."_i18n;
Properties = TYPE_SOLID|PROP_LIFE_DEC|PROP_LIFE_KILL;

View File

@ -29,7 +29,7 @@ void Element::Element_BRCK()
Weight = 100;
HeatConduct = 251;
Description = "Brick, breakable building material.";
Description = "Brick, breakable building material."_i18n;
Properties = TYPE_SOLID|PROP_HOT_GLOW;

View File

@ -29,7 +29,7 @@ void Element::Element_BREC()
Weight = 90;
HeatConduct = 211;
Description = "Broken electronics. Formed from EMP blasts, and when constantly sparked while under pressure, turns to EXOT.";
Description = "Broken electronics. Formed from EMP blasts, and when constantly sparked while under pressure, turns to EXOT."_i18n;
Properties = TYPE_PART|PROP_CONDUCTS|PROP_LIFE_DEC|PROP_HOT_GLOW;

View File

@ -29,7 +29,7 @@ void Element::Element_BRMT()
Weight = 90;
HeatConduct = 211;
Description = "Broken metal. Created when iron rusts or when metals break from pressure.";
Description = "Broken metal. Created when iron rusts or when metals break from pressure."_i18n;
Properties = TYPE_PART|PROP_CONDUCTS|PROP_LIFE_DEC|PROP_HOT_GLOW;

View File

@ -29,7 +29,7 @@ void Element::Element_BTRY()
Weight = 100;
HeatConduct = 251;
Description = "Battery. Generates infinite electricity.";
Description = "Battery. Generates infinite electricity."_i18n;
Properties = TYPE_SOLID;

View File

@ -31,7 +31,7 @@ void Element::Element_BVBR()
DefaultProperties.temp = 273.15f;
HeatConduct = 164;
Description = "Broken vibranium.";
Description = "Broken vibranium."_i18n;
Properties = TYPE_PART|PROP_LIFE_DEC;

View File

@ -30,7 +30,7 @@ void Element::Element_C5()
Weight = 100;
HeatConduct = 88;
Description = "Cold explosive, set off by anything cold.";
Description = "Cold explosive, set off by anything cold."_i18n;
Properties = TYPE_SOLID | PROP_NEUTPENETRATE | PROP_LIFE_DEC;

View File

@ -29,7 +29,7 @@ void Element::Element_CAUS()
Weight = 1;
HeatConduct = 70;
Description = "Caustic Gas, acts like ACID.";
Description = "Caustic Gas, acts like ACID."_i18n;
Properties = TYPE_GAS|PROP_DEADLY;

View File

@ -31,7 +31,7 @@ void Element::Element_CBNW()
DefaultProperties.temp = R_TEMP - 2.0f + 273.15f;
HeatConduct = 29;
Description = "Carbonated water. Slowly releases CO2.";
Description = "Carbonated water. Slowly releases CO2."_i18n;
Properties = TYPE_LIQUID|PROP_CONDUCTS|PROP_LIFE_DEC|PROP_NEUTPENETRATE;

Some files were not shown because too many files have changed in this diff Show More