First pass at string management

This commit is contained in:
Zack Rauen 2019-06-25 16:36:34 -04:00
parent 22e3072304
commit be095fb75f
25 changed files with 444 additions and 404 deletions

File diff suppressed because one or more lines are too long

2
js/main.min.js vendored

File diff suppressed because one or more lines are too long

View File

@ -1,5 +1,5 @@
import Builtin from "../structs/builtin";
import {Settings, DataStore, React, WebpackModules, Events, DOMManager} from "modules";
import {Settings, DataStore, React, WebpackModules, Events, DOMManager, Strings} from "modules";
import CSSEditor from "../ui/customcss/csseditor";
import FloatingWindowContainer from "../ui/floating/container";
import SettingsTitle from "../ui/settings/title";
@ -30,9 +30,9 @@ export default new class CustomCSS extends Builtin {
if (window.require.original) window.require = window.require.original;
});
}
Settings.registerPanel(this.id, this.name, {
Settings.registerPanel(this.id, Strings.Panels.customcss, {
order: 2,
element: () => [<SettingsTitle text="Custom CSS Editor" />, React.createElement(CSSEditor, {
element: () => [<SettingsTitle text={Strings.CustomCSS.editorTitle} />, React.createElement(CSSEditor, {
css: this.savedCss,
save: this.saveCSS.bind(this),
update: this.insertCSS.bind(this),
@ -138,7 +138,7 @@ export default new class CustomCSS extends Builtin {
if (!editorRef || !editorRef.current || !editorRef.current.resize) return;
editorRef.current.resize();
},
title: "Custom CSS Editor",
title: Strings.CustomCSS.editorTitle,
id: "floating-editor-window",
height: 470,
width: 410,
@ -149,7 +149,7 @@ export default new class CustomCSS extends Builtin {
if (!editorRef || !editorRef.current) return false;
return editorRef.current.hasUnsavedChanges;
},
confirmationText: "You have unsaved changes to your Custom CSS. Closing this window will lose all those changes."
confirmationText: Strings.CustomCSS.confirmationText
});
this.isDetached = true;
UserSettings.close();

View File

@ -1,5 +1,5 @@
import Builtin from "../structs/builtin";
import {DiscordModules} from "modules";
import {DiscordModules, Strings} from "modules";
export default new class DeveloperMode extends Builtin {
get name() {return "DeveloperMode";}
@ -68,7 +68,7 @@ export default new class DeveloperMode extends Builtin {
DiscordModules.ElectronModule.copy(this.lastSelector);
cm.hide();
}
}).append($("<span/>", {text: "Copy Selector"}));
}).append($("<span/>", {text: Strings.Collections.settings.developer.copySelector.name}));
cmo.append(cmi);
cm.append(cmo);
if (cm.hasClass("undefined")) cm.css("top", "-=" + cmo.outerHeight());

View File

@ -1,7 +1,7 @@
import Builtin from "../structs/builtin";
import {Config, EmoteInfo, EmoteConfig} from "data";
import {Utilities, WebpackModules, DataStore, DiscordModules, Events, Settings} from "modules";
import {Utilities, WebpackModules, DataStore, DiscordModules, Events, Settings, Strings} from "modules";
import BDEmote from "../ui/emote";
import Toasts from "../ui/toasts";
// import EmoteMenu from "./emotemenu";
@ -65,7 +65,7 @@ export default new class EmoteModule extends Builtin {
}
async enabled() {
Settings.registerCollection("emotes", "Emotes", EmoteConfig, {title: "Clear Emote Cache", onClick: () => { this.clearEmoteData(); this.loadEmoteData(EmoteInfo); }});
Settings.registerCollection("emotes", "Emotes", EmoteConfig, {title: Strings.Emotes.clearEmotes, onClick: () => { this.clearEmoteData(); this.loadEmoteData(EmoteInfo); }});
// Disable emote module for now because it's annoying and slow
// await this.getBlacklist();
// await this.loadEmoteData(EmoteInfo);
@ -216,7 +216,7 @@ export default new class EmoteModule extends Builtin {
}
if (!Settings.get(this.category, "general", "download")) return;
Toasts.show("Downloading emotes in the background do not reload.", {type: "info"});
Toasts.show(Strings.Emotes.downloading, {type: "info"});
for (const e in emoteInfo) {
await new Promise(r => setTimeout(r, 1000));
@ -224,7 +224,7 @@ export default new class EmoteModule extends Builtin {
Emotes[emoteInfo[e].variable] = data;
}
Toasts.show("All emotes successfully downloaded.", {type: "success"});
Toasts.show(Strings.Emotes.downloaded, {type: "success"});
try { _fs.writeFileSync(file, JSON.stringify(Emotes), "utf8"); }
catch (err) { this.stacktrace("Could not save emote data.", err); }

View File

@ -1,5 +1,5 @@
import Builtin from "../structs/builtin";
import {DiscordModules, WebpackModules} from "modules";
import {DiscordModules, WebpackModules, Strings} from "modules";
import PublicServersMenu from "../ui/publicservers/menu";
const LayerStack = WebpackModules.getByProps("pushLayer");
@ -29,7 +29,7 @@ export default new class PublicServers extends Builtin {
"id": "bd-pub-li"
}).append($("<div/>", {
"class": "wrapper-25eVIn " + DiscordModules.GuildClasses.circleButtonMask,
"text": "public",
"text": Strings.PublicServers.button,
"id": "bd-pub-button",
"click": () => { this.openPublicServers(); }
}));

View File

@ -5,56 +5,13 @@ export default [
name: "General",
collapsible: true,
settings: [
{
type: "switch",
id: "download",
name: "Download Emotes",
note: "Download emotes once a week to stay up to date",
value: true
},
{
type: "switch",
id: "emoteMenu",
name: "Emote Menu",
note: "Show Twitch/Favourite emotes in emote menu",
value: true
},
{
type: "switch",
id: "hideEmojiMenu",
name: "Hide Emoji Menu",
note: "Hides Discord's emoji menu when using emote menu",
value: false,
enableWith: "emoteMenu"
},
{
type: "switch",
id: "autoCaps",
name: "Emote Autocapitalization",
note: "Autocapitalize emote commands",
value: false
},
{
type: "switch",
id: "showNames",
name: "Show Names",
note: "Show emote names on hover",
value: true
},
{
type: "switch",
id: "modifiers",
name: "Show Emote Modifiers",
note: "Enable emote mods (flip, spin, pulse, spin2, spin3, 1spin, 2spin, 3spin, tr, bl, br, shake, shake2, shake3, flap)",
value: true
},
{
type: "switch",
id: "animateOnHover",
name: "Animate On Hover",
note: "Only animate the emote modifiers on hover",
value: false
}
{type: "switch", id: "download", value: true},
{type: "switch", id: "emoteMenu", value: true},
{type: "switch", id: "hideEmojiMenu", value: false, enableWith: "emoteMenu"},
{type: "switch", id: "autoCaps", value: false},
{type: "switch", id: "showNames", value: true},
{type: "switch", id: "modifiers", value: true},
{type: "switch", id: "animateOnHover", value: false}
]
},
{
@ -63,27 +20,9 @@ export default [
name: "Categories",
collapsible: true,
settings: [
{
type: "switch",
id: "twitch",
name: "Twitch",
note: "Show Twitch global & subscriber emotes",
value: true
},
{
type: "switch",
id: "ffz",
name: "FrankerFaceZ",
note: "Show emotes from FFZ",
value: true
},
{
type: "switch",
id: "bttv",
name: "BetterTTV",
note: "Show emotes from BTTV",
value: true
}
{type: "switch", id: "", value: true},
{type: "switch", id: "ffz", value: true},
{type: "switch", id: "bttv", value: true}
]
}
];

View File

@ -2,211 +2,68 @@ export default [
{
type: "category",
id: "general",
name: "General",
collapsible: true,
settings: [
{
type: "switch",
id: "emotes",
name: "Emote System",
note: "Enables BD's emote system",
value: true
},
{
type: "switch",
id: "publicServers",
name: "Public Servers",
note: "Display public servers button",
value: true
},
{
type: "switch",
id: "voiceDisconnect",
name: "Voice Disconnect",
note: "Disconnect from voice server when closing Discord",
value: false
},
{
type: "switch",
id: "twentyFourHour",
name: "24 Hour Timestamps",
note: "Hides channels when in minimal mode",
value: false,
},
{
type: "switch",
id: "classNormalizer",
name: "Normalize Classes",
note: "Adds stable classes to elements to help themes. (e.g. adds .da-channels to .channels-Ie2l6A)",
value: true
},
{
type: "switch",
id: "showToasts",
name: "Show Toasts",
note: "Shows a small notification for important information",
value: true
}
{type: "switch", id: "emotes", value: true},
{type: "switch", id: "publicServers", value: true},
{type: "switch", id: "voiceDisconnect", value: false},
{type: "switch", id: "twentyFourHour", value: false},
{type: "switch", id: "classNormalizer", value: true},
{type: "switch", id: "showToasts", value: true}
]
},
{
type: "category",
id: "appearance",
name: "Appearance",
collapsible: true,
settings: [
{
type: "switch",
id: "voiceMode",
name: "Voice Mode",
note: "Hides everything that isn't voice chat",
value: false
},
{
type: "switch",
id: "minimalMode",
name: "Minimal Mode",
note: "Hide elements and reduce the size of elements",
value: false
},
{
type: "switch",
id: "hideChannels",
name: "Hide Channels",
note: "Hides channels when in minimal mode",
value: false,
enableWith: "minimalMode"
},
{
type: "switch",
id: "darkMode",
name: "Dark Mode",
note: "Make certain elements dark by default",
value: true
},
{
type: "switch",
id: "coloredText",
name: "Colored Text",
note: "Make text colour the same as role color",
value: false
}
{type: "switch", id: "voiceMode", value: false},
{type: "switch", id: "minimalMode", value: false},
{type: "switch", id: "hideChannels", value: false, enableWith: "minimalMode"},
{type: "switch", id: "darkMode", value: true},
{type: "switch", id: "coloredText", value: false}
]
},
{
type: "category",
id: "content",
name: "Content Manager",
id: "addons",
collapsible: true,
settings: [
{
type: "switch",
id: "contentErrors",
name: "Show Content Errors",
note: "Shows a modal with plugin/theme errors",
value: true
},
{
type: "switch",
id: "autoScroll",
name: "Scroll To Settings",
note: "Auto-scrolls to a plugin's settings when the button is clicked (only if out of view)",
value: true
},
{
type: "switch",
id: "autoReload",
name: "Automatic Loading",
note: "Automatically loads, reloads, and unloads plugins and themes",
value: true
}
]
},
{
type: "category",
id: "developer",
name: "Developer Settings",
collapsible: true,
shown: false,
settings: [
{
type: "switch",
id: "developerMode",
name: "Developer Mode",
note: "Allows activating debugger when pressing F8",
value: false
},
{
type: "switch",
id: "copySelector",
name: "Copy Selector",
note: "Adds a \"Copy Selector\" option to context menus when developer mode is active",
value: false,
enableWith: "developerMode"
}
]
},
{
type: "category",
id: "window",
name: "Window Preferences",
collapsible: true,
shown: false,
settings: [
{
type: "switch",
id: "transparency",
name: "Enable Transparency",
note: "Enables the main window to be see-through (requires restart)",
value: false
},
{
type: "switch",
id: "frame",
name: "Window Frame",
note: "Adds the native os window frame to the main window",
value: false,
hidden: true
}
{type: "switch", id: "addonErrors", value: true},
{type: "switch", id: "autoScroll", value: true},
{type: "switch", id: "autoReload", value: true}
]
},
{
type: "category",
id: "customcss",
name: "Custom CSS",
collapsible: true,
shown: false,
settings: [
{
type: "switch",
id: "customcss",
name: "Custom CSS",
note: "Enables the Custom CSS tab",
value: true
},
{
type: "switch",
id: "liveUpdate",
name: "Live Update",
note: "Updates the css as you type",
value: false
},
{
type: "switch",
id: "startDetached",
name: "Start Detached",
note: "Clicking the Custom CSS tab opens the editor in a separate window",
value: false,
disableWith: "nativeOpen"
},
{
type: "switch",
id: "nativeOpen",
name: "Open in Native Editor",
note: "Clicking the Custom CSS tab opens your custom css in your native editor",
value: false,
disableWith: "startDetached"
}
{type: "switch", id: "customcss", value: true},
{type: "switch", id: "liveUpdate", value: false},
{type: "switch", id: "startDetached", value: false, disableWith: "nativeOpen"},
{type: "switch", id: "nativeOpen", value: false, disableWith: "startDetached"}
]
},
{
type: "category",
id: "developer",
collapsible: true,
shown: false,
settings: [
{type: "switch", id: "developerMode", value: false},
{type: "switch", id: "copySelector", value: false, enableWith: "developerMode"}
]
},
{
type: "category",
id: "window",
collapsible: true,
shown: false,
settings: [
{type: "switch", id: "transparency", value: false},
{type: "switch", id: "frame", value: false, hidden: true}
]
}
];

View File

@ -1,39 +1,221 @@
export default {
en: {
Settings: {
PublicServers: {name: "Public Servers", description: "Display public servers button"},
MinimalMode: {name: "Minimal Mode", description: "Hide elements and reduce the size of elements."},
VoiceMode: {name: "Voice Mode", description: "Only show voice chat"},
HideChannels: {name: "Hide Channels", description: "Hide channels in minimal mode"},
DarkMode: {name: "Dark Mode", description: "Make certain elements dark by default"},
VoiceDisconnect: {name: "Voice Disconnect", description: "Disconnect from voice server when closing Discord"},
Timestamps: {name: "24 Hour Timestamps", description: "Replace 12hr timestamps with proper ones"},
ColoredText: {name: "Colored Text", description: "Make text colour the same as role colour"},
BDBlue: {name: "BandagedBD Blue", description: "Replace Discord blue with BD Blue"},
DeveloperMode: {name: "Developer Mode", description: "Developer Mode"},
ContentErrors: {name: "Content Error Modals", description: "Shows a modal with plugin/theme errors"},
Toasts: {name: "Show Toasts", description: "Shows a small notification for important information"},
Scroll: {name: "Scroll to Settings", description: "Auto-scrolls to a plugin's settings when the button is clicked (only if out of view)"},
AnimateOnHover: {name: "Animate On Hover", description: "Only animate the emote modifiers on hover"},
CopySelector: {name: "Copy Selector", description: "Adds a \"Copy Selector\" option to context menus when developer mode is active"},
DownloadEmotes: {name: "Download Emotes", description: "Download emotes when the cache is expired"},
NormalizeClasses: {name: "Normalize Classes", description: "Adds stable classes to elements to help themes. (e.g. adds .da-channels to .channels-Ie2l6A)"},
AutomaticLoading: {name: "Automatic Loading", description: "Automatically loads, reloads, and unloads plugins and themes"},
Transparency: {name: "Enable Transparency", description: "Enables the main window to be see-through (requires restart)"},
Twitch: {name: "Twitch Emotes", description: "Show Twitch emotes"},
FFZ: {name: "FrankerFaceZ Emotes", description: "Show FrankerFaceZ Emotes"},
BTTV: {name: "BetterTTV Emotes", description: "Show BetterTTV Emotes"},
EmoteMenu: {name: "Emote Menu", description: "Show Twitch/Favourite emotes in emote menu"},
EmojiMenu: {name: "Emoji Menu", description: "Show Discord emoji menu"},
AutoCaps: {name: "Auto Capitalization", description: "Autocapitalize emote commands"},
ShowNames: {name: "Show Names", description: "Show emote names on hover"},
Modifiers: {name: "Emote Modifiers", description: "Enable emote mods (flip, spin, pulse, spin2, spin3, 1spin, 2spin, 3spin, tr, bl, br, shake, shake2, shake3, flap)"}
Panels: {
plugins: "Plugins",
themes: "Themes",
customcss: "Custom CSS"
},
Collections: {
settings: {
name: "Settings",
general: {
name: "General",
emotes: {
name: "Emote System",
note: "Enables BD's emote system"
},
publicServers: {
name: "Public Servers",
note: "Display public servers button"
},
voiceDisconnect: {
name: "Voice Disconnect",
note: "Disconnect from voice server when closing Discord"
},
twentyFourHour: {
name: "24-Hour Timestamps",
note: "Hides channels when in minimal mode"
},
classNormalizer: {
name: "Normalize Classes",
note: "Adds stable classes to elements to help themes. (e.g. adds .da-channels to .channels-Ie2l6A)"
},
showToasts: {
name: "Show Toasts",
note: "Shows a small notification for important information"
}
},
appearance: {
name: "Appearance",
voiceMode: {
name: "Voice Mode",
note: "Hides everything that isn't voice chat"
},
minimalMode: {
name: "Minimal Mode",
note: "Hide elements and reduce the size of elements"
},
hideChannels: {
name: "Hide Channels",
note: "Hides channels when in minimal mode"
},
darkMode: {
name: "Dark Mode",
note: "Make certain elements dark by default"
},
coloredText: {
name: "Colored Text",
note: "Make text colour the same as role color"
}
},
addons: {
name: "Addon Manager",
addonErrors: {
name: "Show Addon Errors",
note: "Shows a modal with plugin/theme errors"
},
autoScroll: {
name: "Scroll To Settings",
note: "Auto-scrolls to a plugin's settings when the button is clicked (only if out of view)"
},
autoReload: {
name: "Automatic Loading",
note: "Automatically loads, reloads, and unloads plugins and themes"
},
},
customcss: {
name: "Custom CSS",
customcss: {
name: "Custom CSS",
note: "Enables the Custom CSS tab"
},
liveUpdate: {
name: "Live Update",
note: "Updates the css as you type"
},
startDetached: {
name: "Start Detached",
note: "Clicking the Custom CSS tab opens the editor in a separate window",
},
nativeOpen: {
name: "Open in Native Editor",
note: "Clicking the Custom CSS tab opens your custom css in your native editor"
}
},
developer: {
name: "Developer Settings",
developerMode: {
name: "Developer Mode",
note: "Allows activating debugger when pressing F8"
},
copySelector: {
name: "Copy Selector",
note: "Adds a \"Copy Selector\" option to context menus when developer mode is active"
}
},
window: {
name: "Window Preferences",
transparency: {
name: "Enable Transparency",
note: "Enables the main window to be see-through (requires restart)"
},
frame: {
name: "Window Frame",
note: "Adds the native os window frame to the main window"
}
}
},
emotes: {
name: "Emotes",
general: {
name: "General",
download: {
name: "Download Emotes",
note: "Download emotes once a week to stay up to date"
},
emoteMenu: {
name: "Emote Menu",
note: "Show Twitch/Favourite emotes in emote menu"
},
hideEmojiMenu: {
name: "Hide Emoji Menu",
note: "Hides Discord's emoji menu when using emote menu"
},
autoCaps: {
name: "Emote Autocapitalization",
note: "Autocapitalize emote commands"
},
showNames: {
name: "Show Names",
note: "Show emote names on hover"
},
modifiers: {
name: "Show Emote Modifiers",
note: "Enable emote mods (flip, spin, pulse, spin2, spin3, 1spin, 2spin, 3spin, tr, bl, br, shake, shake2, shake3, flap)"
},
animateOnHover: {
name: "Animate On Hover",
note: "Only animate the emote modifiers on hover"
}
},
categories: {
name: "Categories",
twitch: {
name: "Twitch",
note: "Show Twitch global & subscriber emotes"
},
ffz: {
name: "FrankerFaceZ",
note: "Show emotes from FFZ"
},
bttv: {
name: "BetterTTV",
note: "Show emotes from BTTV"
}
}
}
},
Emotes: {
downloading: "Downloading emotes in the background do not reload.",
downloaded: "All emotes successfully downloaded.",
clearEmotes: "Clear Emote Data",
favoriteAction: "Favorite!"
},
CustomCSS: {
confirmationText: "You have unsaved changes to your Custom CSS. Closing this window will lose all those changes.",
update: "Update",
save: "Save",
openNative: "Open in System Editor",
openDetached: "Detach Window",
settings: "Editor Settings",
editorTitle: "Custom CSS Editor"
},
PublicServers: {
button: "public",
join: "Join",
joining: "Joining",
joined: "Joined",
loading: "Loading",
loadMore: "Load More",
notConnected: "Not connected to DiscordServers.com!",
search: "Search",
connect: "Connect",
reconnect: "Reconnect",
categories: "Categories",
connection: "Connected as: {{username}}#{{discriminator}}",
results: "Showing {{start}}-{{end}} of {{total}} results in {{category}}",
query: "for {{query}}"
},
Modals: {
confirmClose: "Are You Sure?",
okay: "Okay",
cancel: "Cancel",
name: "Name",
message: "Message",
error: "Error",
addonErrors: "Addon Errors"
}
},
es: {
Settings: {
PublicServers: {name: "Public Sefasasfasfasfrvers", description: "Display public servers button"},
MinimalMode: {name: "Minafimal Mode", description: "Hide elements and reduce the size of elements."}
Collections: {
settings: {
name: "Ajustes",
addons: {
addonErrors: {
name: "Mostrar Errores de Addons"
}
}
}
}
}
};

View File

@ -22,15 +22,15 @@ const stripBOM = function(content) {
return content;
};
export default class ContentManager {
export default class AddonManager {
get name() {return "";}
get moduleExtension() {return "";}
get extension() {return "";}
get contentFolder() {return "";}
get prefix() {return "content";}
get prefix() {return "addon";}
get collection() {return "settings";}
get category() {return "content";}
get category() {return "addons";}
get id() {return "autoReload";}
emit(event, ...args) {return Events.emit(`${this.prefix}-${event}`, ...args);}

View File

@ -13,3 +13,4 @@ export {default as DOMManager} from "./dommanager";
export {default as Logger} from "./logger";
export {default as Patcher} from "./patcher";
export {default as ReactComponents} from "./reactcomponents";
export {default as Strings} from "./strings";

View File

@ -4,6 +4,7 @@ import ContentManager from "./contentmanager";
import Utilities from "./utilities";
import ContentError from "../structs/contenterror";
import Settings from "./settingsmanager";
import Strings from "./strings";
import Toasts from "../ui/toasts";
import Modals from "../ui/modals";
@ -32,7 +33,7 @@ export default new class PluginManager extends ContentManager {
initialize() {
const errors = super.initialize();
this.setupFunctions();
Settings.registerPanel("plugins", "Plugins", {element: () => SettingsRenderer.getContentPanel("Plugins", this.contentList, this.state, {
Settings.registerPanel("plugins", Strings.Panels.plugins, {element: () => SettingsRenderer.getContentPanel(Strings.Panels.plugins, this.contentList, this.state, {
folder: this.contentFolder,
onChange: this.togglePlugin.bind(this),
reload: this.reloadPlugin.bind(this),

View File

@ -2,13 +2,8 @@ import {SettingsConfig} from "data";
import Logger from "./logger";
import DataStore from "./datastore";
import Events from "./emitter";
// import WebpackModules from "./webpackmodules";
import DiscordModules from "./discordmodules";
// import Patcher from "./patcher";
// import ReactComponents from "./reactcomponents";
// import SettingsRenderer from "../ui/settings/settings";
// import Utilities from "./utilities";
import Strings from "./strings";
export default new class SettingsManager {
@ -17,10 +12,13 @@ export default new class SettingsManager {
this.collections = [];
this.panels = [];
this.registerCollection("settings", "Settings", SettingsConfig);
this.updateStrings = this.updateStrings.bind(this);
}
initialize() {
this.loadSettings();
this.updateStrings();
Events.on("strings-updated", this.updateStrings);
// this.patchSections();
}
@ -166,4 +164,35 @@ export default new class SettingsManager {
Events.on("setting-updated", handler);
return () => {Events.off("setting-updated", handler);};
}
updateStrings() {
// Update settings collections
for (let c = 0; c < this.collections.length; c++) {
const collection = this.collections[c];
const CS = Strings.Collections[collection.id];
if (!CS) continue;
collection.name = CS.name || collection.name;
const categories = this.collections[c].settings;
for (let cat = 0; cat < categories.length; cat++) {
const category = categories[cat];
const CatStr = CS[category.id];
if (!CatStr) continue;
category.name = CatStr.name || category.name;
for (let s = 0; s < category.settings.length; s++) {
const setting = category.settings[s];
const SetStr = CatStr[setting.id];
if (!SetStr) continue;
setting.name = SetStr.name || setting.name;
setting.note = SetStr.note || setting.note;
}
}
}
// Update panel labels
for (let p = 0; p < this.panels.length; p++) {
const panel = this.panels[p];
const Str = Strings.Panels[panel.id];
panel.name = Str || panel.name;
}
}
};

View File

@ -1,6 +1,8 @@
import DiscordModules from "./discordmodules";
import RawStrings from "../data/strings";
import Utilities from "./utilities";
import FormattableString from "../structs/string";
import Events from "./emitter";
const {Dispatcher, DiscordConstants} = DiscordModules;
const Messages = {};
@ -8,7 +10,8 @@ const Messages = {};
export let currentLocale = "en";
export function setLocale(newLocale) {
currentLocale = newLocale;
Utilities.extend(Messages, RawStrings[currentLocale]);
Utilities.extend(Messages, RawStrings[currentLocale]);
Events.emit("strings-updated");
}
Utilities.extend(Messages, RawStrings[currentLocale]);
@ -20,10 +23,17 @@ Dispatcher.subscribe(DiscordConstants.ActionTypes.USER_SETTINGS_UPDATE, ({settin
export default new Proxy(Messages, {
get: function(strings, category) {
if (strings.hasOwnProperty(category)) return strings[category];
return new Proxy({}, {
get: function() {
return `String group "${category}" not found.`;
if (!strings.hasOwnProperty(category)) {
return new Proxy({}, {
get: function() {
return `String group "${category}" not found.`;
}
});
}
return new Proxy(strings[category], {
get: function(obj, prop) {
if (typeof(obj[prop]) == "string") return new FormattableString(obj[prop]);
return obj[prop];
}
});
}

View File

@ -2,6 +2,7 @@ import {Config} from "data";
import ContentManager from "./contentmanager";
import Settings from "./settingsmanager";
import DOMManager from "./dommanager";
import Strings from "./strings";
import Toasts from "../ui/toasts";
import Modals from "../ui/modals";
@ -18,7 +19,7 @@ export default new class ThemeManager extends ContentManager {
initialize() {
const errors = super.initialize();
Settings.registerPanel("themes", "Themes", {element: () => SettingsRenderer.getContentPanel("Themes", this.contentList, this.state, {
Settings.registerPanel("themes", Strings.Panels.themes, {element: () => SettingsRenderer.getContentPanel(Strings.Panels.themes, this.contentList, this.state, {
folder: this.contentFolder,
onChange: this.toggleTheme.bind(this),
reload: this.reloadTheme.bind(this),

7
src/structs/string.js Normal file
View File

@ -0,0 +1,7 @@
import Utilities from "../modules/utilities";
export default class FormattableString extends String {
format(values) {
return Utilities.formatString(this, values);
}
}

View File

@ -1,4 +1,4 @@
import {React, Settings, Events} from "modules";
import {React, Settings, Events, Strings} from "modules";
import Editor from "./editor";
// import Checkbox from "./checkbox";
@ -24,13 +24,13 @@ export default class CssEditor extends React.Component {
this.updateEditor = this.updateEditor.bind(this);
this.controls = [
{label: React.createElement(Refresh, {size: "18px"}), tooltip: "Update", onClick: this.updateCss},
{label: React.createElement(Save, {size: "18px"}), tooltip: "Save", onClick: this.saveCss},
{label: React.createElement(Edit, {size: "18px"}), tooltip: "Open in System Editor", onClick: this.openNative},
{label: React.createElement(Cog, {size: "18px"}), tooltip: "Editor Settings", onClick: "showSettings"},
{label: "Live Update", type:"checkbox", onChange: this.toggleLiveUpdate, checked: Settings.get("settings", "customcss", "liveUpdate"), side: "right"}
{label: React.createElement(Refresh, {size: "18px"}), tooltip: Strings.CustomCSS.update, onClick: this.updateCss},
{label: React.createElement(Save, {size: "18px"}), tooltip: Strings.CustomCSS.save, onClick: this.saveCss},
{label: React.createElement(Edit, {size: "18px"}), tooltip: Strings.CustomCSS.openNative, onClick: this.openNative},
{label: React.createElement(Cog, {size: "18px"}), tooltip: Strings.CustomCSS.settings, onClick: "showSettings"},
{label: Strings.Collections.settings.developer.liveUpdate.name, type:"checkbox", onChange: this.toggleLiveUpdate, checked: Settings.get("settings", "customcss", "liveUpdate"), side: "right"}
];
if (this.openDetached) this.controls.push({label: React.createElement(Detach, {size: "18px"}), tooltip: "Detach Editor", onClick: this.openDetached, side: "right"});
if (this.openDetached) this.controls.push({label: React.createElement(Detach, {size: "18px"}), tooltip: Strings.CustomCSS.openDetached, onClick: this.openDetached, side: "right"});
}
componentDidMount() {

View File

@ -1,5 +1,4 @@
import {Settings, React, WebpackModules, Events} from "modules";
// import EmoteMenu from "../builtins/emotemenu";
import {Settings, React, WebpackModules, Events, Strings} from "modules";
const TooltipWrapper = WebpackModules.getByDisplayName("TooltipDeprecated");
@ -15,6 +14,7 @@ export default class BDEmote extends React.Component {
this.onMouseEnter = this.onMouseEnter.bind(this);
this.onMouseLeave = this.onMouseLeave.bind(this);
this.onClick = this.onClick.bind(this);
this.toggleFavorite = this.toggleFavorite.bind(this);
}
get animateOnHover() {
@ -43,6 +43,14 @@ export default class BDEmote extends React.Component {
if (this.props.onClick) this.props.onClick(e);
}
toggleFavorite(e) {
e.preventDefault();
e.stopPropagation();
if (this.state.isFavorite) Events.emit("emotes-favorite-removed", this.label);
else Events.emit("emotes-favorite-added", this.label, this.props.url);
this.setState({isFavorite: !this.state.isFavorite});
}
render() {
return React.createElement(TooltipWrapper, {
color: "black",
@ -65,22 +73,9 @@ export default class BDEmote extends React.Component {
}),
React.createElement("input", {
className: "fav" + (this.state.isFavorite ? " active" : ""),
title: "Favorite!",
title: Strings.Emotes.favoriteAction,
type: "button",
onClick: (e) => {
e.preventDefault();
e.stopPropagation();
if (this.state.isFavorite) {
Events.emit("emotes-favorite-removed", this.label);
// delete EmoteMenu.favoriteEmotes[this.label];
// EmoteMenu.updateFavorites();
}
else {
Events.emit("emotes-favorite-added", this.label, this.props.url);
// EmoteMenu.favorite(this.label, this.props.url);
}
this.setState({isFavorite: !this.state.isFavorite});
}
onClick: this.toggleFavorite
})
)
);

View File

@ -1,4 +1,4 @@
import {React} from "modules";
import {React, Strings} from "modules";
import Screen from "../../structs/screen";
import CloseButton from "../icons/close";
@ -99,7 +99,7 @@ export default class FloatingWindow extends React.Component {
confirmClose() {
return new Promise(resolve => {
Modals.showConfirmationModal("Are You Sure?", this.props.confirmationText, {
Modals.showConfirmationModal(Strings.Modals.confirmClose, this.props.confirmationText, {
danger: true,
confirmText: "Close",
onConfirm: () => {resolve(true);},

View File

@ -1,8 +1,8 @@
import {Logger, WebpackModules, Utilities, React, Settings} from "modules";
import {Logger, WebpackModules, Utilities, React, Settings, Strings} from "modules";
export default class Modals {
static get shouldShowContentErrors() {return Settings.get("settings", "content", "contentErrors");}
static get shouldShowContentErrors() {return Settings.get("settings", "addons", "addonErrors");}
static get ModalStack() {return WebpackModules.getByProps("push", "update", "pop", "popWithKey");}
static get AlertModal() {return WebpackModules.getByPrototypes("handleCancel", "handleSubmit", "handleMinorConfirm");}
@ -10,10 +10,13 @@ export default class Modals {
static get ConfirmationModal() {return WebpackModules.getModule(m => m.defaultProps && m.key && m.key() == "confirm-modal");}
static default(title, content) {
const backdrop = WebpackModules.getByProps("backdrop") || {backdrop: "backdrop-1wrmKb"};
const baseModalClasses = WebpackModules.getModule(m => m.modal && m.inner && !m.sizeMedium) || {modal: "modal-36zFtW", inner: "inner-2VEzy9"};
const modalClasses = WebpackModules.getByProps("sizeMedium") || {modal: "backdrop-1wrmKb", sizeMedium: "sizeMedium-ctncE5", content: "content-2KoCOZ", header: "header-2nhbou", footer: "footer-30ewN8", close: "close-hhyjWJ", inner: "inner-2Z5QZX"};
const modal = Utilities.parseHTML(`<div class="bd-modal-wrapper theme-dark">
<div class="bd-backdrop backdrop-1wrmKB"></div>
<div class="bd-modal modal-1UGdnR">
<div class="bd-modal-inner inner-1JeGVc">
<div class="bd-backdrop ${backdrop.backdrop}"></div>
<div class="bd-modal ${baseModalClasses.modal}">
<div class="bd-modal-inner ${baseModalClasses.inner}">
<div class="header header-1R_AjF">
<div class="title">${title}</div>
</div>
@ -24,8 +27,8 @@ export default class Modals {
</div>
</div>
</div>
<div class="footer footer-2yfCgX">
<button type="button">Okay</button>
<div class="footer ${modalClasses.footer}">
<button type="button">${Strings.Modals.okay}</button>
</div>
</div>
</div>
@ -79,8 +82,8 @@ export default class Modals {
header: title,
children: content,
red: danger,
confirmText: confirmText ? confirmText : "Okay",
cancelText: cancelText ? cancelText : "Cancel",
confirmText: confirmText ? confirmText : Strings.Modals.okay,
cancelText: cancelText ? cancelText : Strings.Modals.cancel,
onConfirm: onConfirm ? onConfirm : emptyFunction,
onCancel: onCancel ? onCancel : emptyFunction
}, props));
@ -90,31 +93,34 @@ export default class Modals {
static showContentErrors({plugins: pluginErrors = [], themes: themeErrors = []}) {
if (!pluginErrors || !themeErrors || !this.shouldShowContentErrors) return;
if (!pluginErrors.length && !themeErrors.length) return;
const backdrop = WebpackModules.getByProps("backdrop") || {backdrop: "backdrop-1wrmKb"};
const baseModalClasses = WebpackModules.getModule(m => m.modal && m.inner && !m.sizeMedium) || {modal: "modal-36zFtW", inner: "inner-2VEzy9"};
const modalClasses = WebpackModules.getByProps("sizeMedium") || {modal: "modal-3v8ziU", sizeMedium: "sizeMedium-ctncE5", content: "content-2KoCOZ", header: "header-2nhbou", footer: "footer-30ewN8", close: "close-hhyjWJ", inner: "inner-2Z5QZX"};
const modal = $(`<div class="bd-modal-wrapper theme-dark">
<div class="bd-backdrop backdrop-1wrmKB"></div>
<div class="bd-modal bd-content-modal modal-1UGdnR">
<div class="bd-modal-inner inner-1JeGVc">
<div class="header header-1R_AjF"><div class="title">Content Errors</div></div>
<div class="bd-backdrop ${backdrop.backdrop}"></div>
<div class="bd-modal bd-content-modal ${baseModalClasses.modal}">
<div class="bd-modal-inner ${baseModalClasses.inner}">
<div class="header ${modalClasses.header}"><div class="title">${Strings.Modals.addonErrors}</div></div>
<div class="bd-modal-body">
<div class="tab-bar-container">
<div class="tab-bar TOP">
<div class="tab-bar-item">Plugins</div>
<div class="tab-bar-item">Themes</div>
<div class="tab-bar-item">${Strings.General.plugins}</div>
<div class="tab-bar-item">${Strings.General.themes}</div>
</div>
</div>
<div class="table-header">
<div class="table-column column-name">Name</div>
<div class="table-column column-message">Message</div>
<div class="table-column column-error">Error</div>
<div class="table-column column-name">${Strings.Modals.name}</div>
<div class="table-column column-message">${Strings.Modals.message}</div>
<div class="table-column column-error">${Strings.Modals.error}</div>
</div>
<div class="scroller-wrap fade">
<div class="scroller-wrap fade ${modalClasses.content}">
<div class="scroller">
</div>
</div>
</div>
<div class="footer footer-2yfCgX">
<button type="button">Okay</button>
<div class="footer ${modalClasses.footer}">
<button type="button">${Strings.Modals.okay}</button>
</div>
</div>
</div>

View File

@ -1,4 +1,4 @@
import {React} from "modules";
import {React, Strings} from "modules";
export default class ServerCard extends React.Component {
constructor(props) {
@ -14,7 +14,7 @@ export default class ServerCard extends React.Component {
render() {
const {server} = this.props;
const buttonText = typeof(this.state.joined) == "string" ? "Joining..." : this.state.joined ? "Joined" : "Join";
const buttonText = typeof(this.state.joined) == "string" ? `${Strings.PublicServers.joining}...` : this.state.joined ? Strings.PublicServers.joined : Strings.PublicServers.join;
const buttonClass = `bd-button${this.state.joined == true ? " bd-button-success" : ""}`;
return <div className={`bd-server-card${server.pinned ? " bd-server-card-pinned" : ""}`}>
<img className="bd-server-image" src={server.iconUrl} onError={this.handleError} />,

View File

@ -1,4 +1,4 @@
import {React, WebpackModules} from "modules";
import {React, WebpackModules, Strings} from "modules";
import SettingsTitle from "../settings/title";
import ServerCard from "./card";
import Connection from "../../structs/psconnection";
@ -87,22 +87,22 @@ export default class PublicServers extends React.Component {
}
get searchBox() {
return React.createElement("input", {onKeyDown: this.searchKeyDown, type: "text", className: "bd-search", placeholder: "Search...", maxLength: "50"});
return React.createElement("input", {onKeyDown: this.searchKeyDown, type: "text", className: "bd-search", placeholder: `${Strings.PublicServers.search}...`, maxLength: "50"});
}
get title() {
if (!this.state.user) return "Not connected to DiscordServers.com!";
if (this.state.loading) return "Loading...";
if (!this.state.user) return Strings.PublicServers.notConnected;
if (this.state.loading) return `${Strings.PublicServers.loading}...`;
const start = this.state.results.from + 1;
const total = this.state.results.total;
const end = this.state.results.next ? this.state.results.next : total;
let title = `Showing ${start}-${end} of ${total} results in ${this.state.category}`;
if (this.state.query) title += ` for ${this.state.query}`;
let title = Strings.PublicServers.results.format({start, end, total, category: this.state.category});
if (this.state.query) title += " " + Strings.PublicServers.query.format({query: this.state.query});
return title;
}
get content() {
const connectButton = this.state.user ? null : {title: "Connect", onClick: this.connect};
const connectButton = this.state.user ? null : {title: Strings.PublicServers.connect, onClick: this.connect};
const pinned = this.state.category == "All" || !this.state.user ? this.bdServer : null;
const servers = this.state.results.servers.map((server) => {
return React.createElement(ServerCard, {key: server.identifier, server: server, joined: Connection.hasJoined(server.identifier), defaultAvatar: Connection.getDefaultAvatar});
@ -115,15 +115,15 @@ export default class PublicServers extends React.Component {
}
get nextButton() {
return React.createElement("button", {type: "button", className: "bd-button bd-button-next", onClick: this.loadNextPage}, this.state.loading ? "Loading" : "Load More");
return React.createElement("button", {type: "button", className: "bd-button bd-button-next", onClick: this.loadNextPage}, this.state.loading ? Strings.PublicServers.loading : Strings.PublicServers.loadMore);
}
get connection() {
const {user} = this.state;
if (!user) return React.createElement("div", {id: "bd-connection"});
return React.createElement("div", {id: "bd-connection"},
React.createElement("div", {className: "bd-footnote"}, `Connected as: `, `${user.username}#${user.discriminator}`),
React.createElement("button", {type: "button", className: "bd-button bd-button-reconnect", onClick: this.connect}, "Reconnect")
React.createElement("div", {className: "bd-footnote"}, Strings.PublicServers.connection.format(user)),
React.createElement("button", {type: "button", className: "bd-button bd-button-reconnect", onClick: this.connect}, Strings.PublicServers.reconnect)
);
}
@ -155,12 +155,12 @@ export default class PublicServers extends React.Component {
onSetSection: this.changeCategory,
section: this.state.category,
sections: [
{section: "HEADER", label: "Search"},
{section: "HEADER", label: Strings.PublicServers.search},
{section: "CUSTOM", element: () => this.searchBox},
{section: "HEADER", label: "Categories"},
{section: "HEADER", label: Strings.PublicServers.categories},
...categories,
{section: "DIVIDER"},
{section: "HEADER", label: React.createElement("a", {href: "https://discordservers.com", target: "_blank"}, "Discordservers.com")},
{section: "HEADER", label: React.createElement("a", {href: "https://discordservers.com", target: "_blank"}, "DiscordServers.com")},
{section: "DIVIDER"},
{section: "CUSTOM", element: () => this.connection}
],

View File

@ -1,7 +1,7 @@
// static getPluginsPanel(plugins, state, options = {}) {
// const {folder = "", onChange, reload} = options;
// const titleComponent = React.createElement(SettingsTitle, {text: "Plugins", button: {title: "Open Plugin Folder", onClick: () => { require("electron").shell.openItem(folder); }}});
// const cards = plugins.sort((a, b) => a.name.toLowerCase().localeCompare(b.name.toLowerCase())).map(plugin =>
// const cards = plugins.sort((a, b) => a.name.toLowerCase().localeCompare(b.name.toLowerCase())).map(plugin =>
// React.createElement(PluginCard, {key: plugin.id, enabled: state[plugin.id], content: plugin, onChange, reload})
// );
// return [titleComponent, React.createElement("ul", {className: "bda-slist"}, ...cards)];
@ -23,7 +23,7 @@ export default class ContentList extends React.Component {
render() {
const {title, folder, contentList, contentState, onChange, reload} = this.props;
const showReloadIcon = !Settings.get("settings", "content", "autoReload");
const showReloadIcon = !Settings.get("settings", "addons", "autoReload");
const button = folder ? {title: `Open ${title} Folder`, onClick: () => {require("electron").shell.openItem(folder);}} : null;
return [
<SettingsTitle key="title" text={title} button={button} otherChildren={showReloadIcon && <ReloadIcon className="bd-reload" onClick={this.reload.bind(this)} />} />,

View File

@ -95,7 +95,7 @@ export default class PluginCard extends React.Component {
React.createElement("span", {className: "bda-author"}, author)
),
React.createElement("div", {className: "bda-controls"},
!Settings.get("settings", "content", "autoReload") && React.createElement(ReloadIcon, {className: "bd-reload bd-reload-card", onClick: this.reload}),
!Settings.get("settings", "addons", "autoReload") && React.createElement(ReloadIcon, {className: "bd-reload bd-reload-card", onClick: this.reload}),
React.createElement("label", {className: "ui-switch-wrapper ui-flex-child", style: {flex: "0 0 auto"}},
React.createElement("input", {checked: this.state.checked, onChange: this.onChange, className: "ui-switch-checkbox", type: "checkbox"}),
React.createElement("div", {className: this.state.checked ? "ui-switch checked" : "ui-switch"})

View File

@ -39,7 +39,7 @@ export default class ThemeCard extends React.Component {
React.createElement("span", {className: "bda-author"}, author)
),
React.createElement("div", {className: "bda-controls"},
!Settings.get("settings", "content", "autoReload") && React.createElement(ReloadIcon, {className: "bd-reload bd-reload-card", onClick: this.reload}),
!Settings.get("settings", "addons", "autoReload") && React.createElement(ReloadIcon, {className: "bd-reload bd-reload-card", onClick: this.reload}),
React.createElement("label", {className: "ui-switch-wrapper ui-flex-child", style: {flex: "0 0 auto"}},
React.createElement("input", {checked: this.state.checked, onChange: this.onChange, className: "ui-switch-checkbox", type: "checkbox"}),
React.createElement("div", {className: this.state.checked ? "ui-switch checked" : "ui-switch"})