Merge branch 'master' into master

This commit is contained in:
Elijah R 2024-04-09 22:18:32 -04:00 committed by GitHub
commit 587d13cd51
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 398 additions and 21 deletions

View File

@ -186,7 +186,7 @@
<a href="https://computernewb.com/collab-vm/faq/" class="nav-link"><i class="fa-solid fa-circle-question"></i> <span id="faqBtnText"></span></a> <a href="https://computernewb.com/collab-vm/faq/" class="nav-link"><i class="fa-solid fa-circle-question"></i> <span id="faqBtnText"></span></a>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a href="https://computernewb.com/collab-vm/rules" class="nav-link"><i class="fa-solid fa-clipboard-check"></i> <span id="rulesBtnText"></span></a> <a id="rulesBtn" href="https://computernewb.com/collab-vm/rules" class="nav-link"><i class="fa-solid fa-clipboard-check"></i> <span id="rulesBtnText"></span></a>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a href="https://discord.gg/a4kqb4mGyX" class="nav-link"><i class="fa-brands fa-discord"></i> Discord</a> <a href="https://discord.gg/a4kqb4mGyX" class="nav-link"><i class="fa-brands fa-discord"></i> Discord</a>

View File

@ -1,5 +1,6 @@
import { StringLike } from './StringLike'; import { StringLike } from './StringLike';
import { Format } from './format'; import { Format } from './format';
import { Emitter, Unsubscribe, createNanoEvents } from 'nanoevents';
/// All string keys. /// All string keys.
export enum I18nStringKey { export enum I18nStringKey {
@ -100,6 +101,11 @@ export enum I18nStringKey {
kNotLoggedIn = 'kNotLoggedIn', kNotLoggedIn = 'kNotLoggedIn',
} }
export interface I18nEvents {
// Called when the language is changed
languageChanged: (lang: string) => void;
}
// This models the JSON structure. // This models the JSON structure.
export type Language = { export type Language = {
languageName: string; languageName: string;
@ -141,13 +147,14 @@ export class I18n {
private langs : Map<string, Language> = new Map<string, Language>(); private langs : Map<string, Language> = new Map<string, Language>();
private lang: Language = fallbackLanguage; private lang: Language = fallbackLanguage;
private languageDropdown: HTMLSpanElement = document.getElementById('languageDropdown') as HTMLSpanElement; private languageDropdown: HTMLSpanElement = document.getElementById('languageDropdown') as HTMLSpanElement;
private emitter: Emitter<I18nEvents> = createNanoEvents();
CurrentLanguage = () => this.langId;
// the ID of the language // the ID of the language
private langId: string = fallbackId; private langId: string = fallbackId;
async Init() { async Init() {
let lang = window.localStorage.getItem('i18n-lang');
// Load language list // Load language list
var res = await fetch("lang/languages.json"); var res = await fetch("lang/languages.json");
if (!res.ok) { if (!res.ok) {
@ -157,7 +164,6 @@ export class I18n {
return; return;
} }
var langData = await res.json() as LanguagesJson; var langData = await res.json() as LanguagesJson;
if (lang === null) lang = langData.defaultLanguage;
for (const langId of langData.languages) { for (const langId of langData.languages) {
let path = `./lang/${langId}.json`; let path = `./lang/${langId}.json`;
let res = await fetch(path); let res = await fetch(path);
@ -181,7 +187,24 @@ export class I18n {
}); });
this.languageDropdown.appendChild(a); this.languageDropdown.appendChild(a);
}); });
if (!this.langs.has(lang)) lang = langData.defaultLanguage; let lang = null;
let lsLang = window.localStorage.getItem('i18n-lang');
var browserLang = navigator.language.toLowerCase();
// If the language is set in localstorage, use that
if (lsLang !== null && this.langs.has(lsLang)) lang = lsLang;
// If the browser language is in the list, use that
else if (this.langs.has(browserLang)) lang = browserLang;
else {
// If the exact browser language isn't in the list, try to find a language with the same prefix
for (let langId of langData.languages) {
if (langId.split('-')[0] === browserLang.split('-')[0]) {
lang = langId;
break;
}
}
}
// If all else fails, use the default language
if (lang === null) lang = langData.defaultLanguage;
this.SetLanguage(this.langs.get(lang) as Language, lang); this.SetLanguage(this.langs.get(lang) as Language, lang);
this.ReplaceStaticStrings(); this.ReplaceStaticStrings();
} }
@ -198,6 +221,8 @@ export class I18n {
if (this.langId !== fallbackId) { if (this.langId !== fallbackId) {
window.localStorage.setItem('i18n-lang', this.langId); window.localStorage.setItem('i18n-lang', this.langId);
} }
this.emitter.emit('languageChanged', this.langId);
console.log('i18n initalized for', id, 'sucessfully!'); console.log('i18n initalized for', id, 'sucessfully!');
} }
@ -208,7 +233,6 @@ export class I18n {
homeBtnText: I18nStringKey.kSiteButtons_Home, homeBtnText: I18nStringKey.kSiteButtons_Home,
faqBtnText: I18nStringKey.kSiteButtons_FAQ, faqBtnText: I18nStringKey.kSiteButtons_FAQ,
rulesBtnText: I18nStringKey.kSiteButtons_Rules, rulesBtnText: I18nStringKey.kSiteButtons_Rules,
accountDropdownUsername: I18nStringKey.kNotLoggedIn,
accountLoginButton: I18nStringKey.kGeneric_Login, accountLoginButton: I18nStringKey.kGeneric_Login,
accountRegisterButton: I18nStringKey.kGeneric_Register, accountRegisterButton: I18nStringKey.kGeneric_Register,
accountSettingsButton: I18nStringKey.kAccountModal_AccountSettings, accountSettingsButton: I18nStringKey.kAccountModal_AccountSettings,
@ -337,6 +361,17 @@ export class I18n {
}, },
}; };
const kDomClassToStringMap: StringKeyMap = {
"mod-end-turn-btn": I18nStringKey.kVMButtons_EndTurn,
"mod-ban-btn": I18nStringKey.kAdminVMButtons_Ban,
"mod-kick-btn": I18nStringKey.kAdminVMButtons_Kick,
"mod-change-username-btn": I18nStringKey.kVMButtons_ChangeUsername,
"mod-temp-mute-btn": I18nStringKey.kAdminVMButtons_TempMute,
"mod-indef-mute-btn": I18nStringKey.kAdminVMButtons_IndefMute,
"mod-unmute-btn": I18nStringKey.kAdminVMButtons_Unmute,
"mod-get-ip-btn": I18nStringKey.kAdminVMButtons_GetIP,
}
for (let domId of Object.keys(kDomIdtoStringMap)) { for (let domId of Object.keys(kDomIdtoStringMap)) {
let element = document.getElementById(domId); let element = document.getElementById(domId);
if (element == null) { if (element == null) {
@ -365,6 +400,13 @@ export class I18n {
element.setAttribute(attr, this.GetStringRaw(attributes[attr] as I18nStringKey)); element.setAttribute(attr, this.GetStringRaw(attributes[attr] as I18nStringKey));
} }
} }
for (let domClass of Object.keys(kDomClassToStringMap)) {
let elements = document.getElementsByClassName(domClass);
for (let element of elements) {
element.innerHTML = this.GetStringRaw(kDomClassToStringMap[domClass]);
}
}
} }
// Returns a (raw, unformatted) string. Currently only used if we don't need formatting. // Returns a (raw, unformatted) string. Currently only used if we don't need formatting.
@ -387,6 +429,10 @@ export class I18n {
GetString(key: I18nStringKey, ...replacements: StringLike[]): string { GetString(key: I18nStringKey, ...replacements: StringLike[]): string {
return Format(this.GetStringRaw(key), ...replacements); return Format(this.GetStringRaw(key), ...replacements);
} }
on<e extends keyof I18nEvents>(event: e, cb: I18nEvents[e]): Unsubscribe {
return this.emitter.on(event, cb);
}
} }
export let TheI18n = new I18n(); export let TheI18n = new I18n();

View File

@ -23,6 +23,7 @@ const elements = {
vmview: document.getElementById('vmview') as HTMLDivElement, vmview: document.getElementById('vmview') as HTMLDivElement,
vmDisplay: document.getElementById('vmDisplay') as HTMLDivElement, vmDisplay: document.getElementById('vmDisplay') as HTMLDivElement,
homeBtn: document.getElementById('homeBtn') as HTMLAnchorElement, homeBtn: document.getElementById('homeBtn') as HTMLAnchorElement,
rulesBtn: document.getElementById('rulesBtn') as HTMLAnchorElement,
chatList: document.getElementById('chatList') as HTMLTableSectionElement, chatList: document.getElementById('chatList') as HTMLTableSectionElement,
chatListDiv: document.getElementById('chatListDiv') as HTMLDivElement, chatListDiv: document.getElementById('chatListDiv') as HTMLDivElement,
userlist: document.getElementById('userlist') as HTMLTableSectionElement, userlist: document.getElementById('userlist') as HTMLTableSectionElement,
@ -825,33 +826,33 @@ function userModOptions(user: { user: User; element: HTMLTableRowElement }) {
td.setAttribute('aria-expanded', 'false'); td.setAttribute('aria-expanded', 'false');
let ul = document.createElement('ul'); let ul = document.createElement('ul');
ul.classList.add('dropdown-menu', 'dropdown-menu-dark', 'table-dark', 'text-light'); ul.classList.add('dropdown-menu', 'dropdown-menu-dark', 'table-dark', 'text-light');
if (perms.bypassturn) addUserDropdownItem(ul, TheI18n.GetString(I18nStringKey.kVMButtons_EndTurn), () => VM!.endTurn(user.user.username)); if (perms.bypassturn) addUserDropdownItem(ul, TheI18n.GetString(I18nStringKey.kVMButtons_EndTurn), () => VM!.endTurn(user.user.username), "mod-end-turn-btn");
if (perms.ban) addUserDropdownItem(ul, TheI18n.GetString(I18nStringKey.kAdminVMButtons_Ban), () => VM!.ban(user.user.username)); if (perms.ban) addUserDropdownItem(ul, TheI18n.GetString(I18nStringKey.kAdminVMButtons_Ban), () => VM!.ban(user.user.username), "mod-ban-btn");
if (perms.kick) addUserDropdownItem(ul, TheI18n.GetString(I18nStringKey.kAdminVMButtons_Kick), () => VM!.kick(user.user.username)); if (perms.kick) addUserDropdownItem(ul, TheI18n.GetString(I18nStringKey.kAdminVMButtons_Kick), () => VM!.kick(user.user.username), "mod-kick-btn");
if (perms.rename) if (perms.rename)
addUserDropdownItem(ul, TheI18n.GetString(I18nStringKey.kVMButtons_ChangeUsername), () => { addUserDropdownItem(ul, TheI18n.GetString(I18nStringKey.kVMButtons_ChangeUsername), () => {
let newname = prompt(TheI18n.GetString(I18nStringKey.kVMPrompts_AdminChangeUsernamePrompt, user.user.username)); let newname = prompt(TheI18n.GetString(I18nStringKey.kVMPrompts_AdminChangeUsernamePrompt, user.user.username));
if (!newname) return; if (!newname) return;
VM!.renameUser(user.user.username, newname); VM!.renameUser(user.user.username, newname);
}); }, "mod-rename-btn");
if (perms.mute) { if (perms.mute) {
addUserDropdownItem(ul, TheI18n.GetString(I18nStringKey.kAdminVMButtons_TempMute), () => VM!.mute(user.user.username, MuteState.Temp)); addUserDropdownItem(ul, TheI18n.GetString(I18nStringKey.kAdminVMButtons_TempMute), () => VM!.mute(user.user.username, MuteState.Temp), "mod-temp-mute-btn");
addUserDropdownItem(ul, TheI18n.GetString(I18nStringKey.kAdminVMButtons_IndefMute), () => VM!.mute(user.user.username, MuteState.Perma)); addUserDropdownItem(ul, TheI18n.GetString(I18nStringKey.kAdminVMButtons_IndefMute), () => VM!.mute(user.user.username, MuteState.Perma), "mod-indef-mute-btn");
addUserDropdownItem(ul, TheI18n.GetString(I18nStringKey.kAdminVMButtons_Unmute), () => VM!.mute(user.user.username, MuteState.Unmuted)); addUserDropdownItem(ul, TheI18n.GetString(I18nStringKey.kAdminVMButtons_Unmute), () => VM!.mute(user.user.username, MuteState.Unmuted), "mod-unmute-btn");
} }
if (perms.grabip) if (perms.grabip)
addUserDropdownItem(ul, TheI18n.GetString(I18nStringKey.kAdminVMButtons_GetIP), async () => { addUserDropdownItem(ul, TheI18n.GetString(I18nStringKey.kAdminVMButtons_GetIP), async () => {
let ip = await VM!.getip(user.user.username); let ip = await VM!.getip(user.user.username);
alert(ip); alert(ip);
}); }, "mod-get-ip-btn");
tr.appendChild(ul); tr.appendChild(ul);
} }
function addUserDropdownItem(ul: HTMLUListElement, text: string, func: () => void) { function addUserDropdownItem(ul: HTMLUListElement, text: string, func: () => void, classname: string) {
let li = document.createElement('li'); let li = document.createElement('li');
let a = document.createElement('a'); let a = document.createElement('a');
a.href = '#'; a.href = '#';
a.classList.add('dropdown-item'); a.classList.add('dropdown-item', classname);
a.innerHTML = text; a.innerHTML = text;
a.addEventListener('click', () => func()); a.addEventListener('click', () => func());
li.appendChild(a); li.appendChild(a);
@ -1249,13 +1250,39 @@ w.VMName = null;
document.addEventListener('DOMContentLoaded', async () => { document.addEventListener('DOMContentLoaded', async () => {
// Initalize the i18n system // Initalize the i18n system
await TheI18n.Init(); await TheI18n.Init();
TheI18n.on('languageChanged', lang => {
// Update all dynamic text
if (VM) {
document.title = Format('{0} - {1}', VM.getNode()!, TheI18n.GetString(I18nStringKey.kGeneric_CollabVM));
if (turn !== -1) {
if (turn === 0) elements.turnstatus.innerText = TheI18n.GetString(I18nStringKey.kVM_TurnTimeTimer, turnTimer);
else elements.turnstatus.innerText = TheI18n.GetString(I18nStringKey.kVM_WaitingTurnTimer, turnTimer);
elements.turnBtnText.innerText = TheI18n.GetString(I18nStringKey.kVMButtons_EndTurn);
}
else
elements.turnBtnText.innerText = TheI18n.GetString(I18nStringKey.kVMButtons_TakeTurn);
if (VM!.getVoteStatus())
elements.voteTimeText.innerText = TheI18n.GetString(I18nStringKey.kVM_VoteForResetTimer, voteTimer);
}
else {
document.title = TheI18n.GetString(I18nStringKey.kGeneric_CollabVM);
}
if (!auth || !auth.account) elements.accountDropdownUsername.innerText = TheI18n.GetString(I18nStringKey.kNotLoggedIn);
if (darkTheme) elements.toggleThemeBtnText.innerHTML = TheI18n.GetString(I18nStringKey.kSiteButtons_LightMode);
else elements.toggleThemeBtnText.innerHTML = TheI18n.GetString(I18nStringKey.kSiteButtons_DarkMode);
});
// Load theme // Load theme
var _darktheme : boolean; var _darktheme : boolean;
if (localStorage.getItem("cvm-dark-theme") === "0") // Check if dark theme is set in local storage
loadColorTheme(false); if (localStorage.getItem("cvm-dark-theme") !== null)
else loadColorTheme(localStorage.getItem("cvm-dark-theme") === "1");
// Otherwise, try to detect the system theme
else if (window.matchMedia('(prefers-color-scheme: dark)').matches)
loadColorTheme(true); loadColorTheme(true);
else
loadColorTheme(false);
// Initialize authentication if enabled // Initialize authentication if enabled
if (Config.Auth.Enabled) { if (Config.Auth.Enabled) {
auth = new AuthManager(Config.Auth.APIEndpoint); auth = new AuthManager(Config.Auth.APIEndpoint);
@ -1268,10 +1295,10 @@ document.addEventListener('DOMContentLoaded', async () => {
await loadList(); await loadList();
// Welcome modal // Welcome modal
let welcomeModal = new bootstrap.Modal(document.getElementById('welcomeModal') as HTMLDivElement);
let noWelcomeModal = window.localStorage.getItem('no-welcome-modal'); let noWelcomeModal = window.localStorage.getItem('no-welcome-modal');
if (noWelcomeModal !== '1') { if (noWelcomeModal !== '1') {
let welcomeModalDismissBtn = document.getElementById('welcomeModalDismiss') as HTMLButtonElement; let welcomeModalDismissBtn = document.getElementById('welcomeModalDismiss') as HTMLButtonElement;
let welcomeModal = new bootstrap.Modal(document.getElementById('welcomeModal') as HTMLDivElement);
welcomeModalDismissBtn.addEventListener('click', () => { welcomeModalDismissBtn.addEventListener('click', () => {
window.localStorage.setItem('no-welcome-modal', '1'); window.localStorage.setItem('no-welcome-modal', '1');
}); });
@ -1281,4 +1308,10 @@ document.addEventListener('DOMContentLoaded', async () => {
welcomeModalDismissBtn.disabled = false; welcomeModalDismissBtn.disabled = false;
}, 5000); }, 5000);
} }
elements.rulesBtn.addEventListener('click', e => {
if (TheI18n.CurrentLanguage() !== "en-us") {
e.preventDefault();
welcomeModal.show();
}
});
}); });

View File

@ -620,6 +620,10 @@ export default class CollabVMClient {
return this.auth; return this.auth;
} }
getNode() {
return this.node;
}
private onInternal<E extends keyof CollabVMClientPrivateEvents>(event: E, callback: CollabVMClientPrivateEvents[E]): Unsubscribe { private onInternal<E extends keyof CollabVMClientPrivateEvents>(event: E, callback: CollabVMClientPrivateEvents[E]): Unsubscribe {
return this.internalEmitter.on(event, callback); return this.internalEmitter.on(event, callback);
} }

98
static/lang/de-de.json Normal file
View File

@ -0,0 +1,98 @@
{
"languageName": "Deutsch",
"translatedLanguageName": "German",
"flag": "🇩🇪",
"author": "julias.zone, nephacks",
"stringKeys": {
"kGeneric_CollabVM": "CollabVM",
"kGeneric_Yes": "Ja",
"kGeneric_No": "Nein",
"kGeneric_Ok": "OK",
"kGeneric_Cancel": "Abbrechen",
"kGeneric_Send": "Senden",
"kGeneric_Understood": "Verstanden",
"kGeneric_Username": "Benutzername",
"kGeneric_Password": "Passwort",
"kGeneric_Login": "Einloggen",
"kGeneric_Register": "Registrieren",
"kGeneric_EMail": "E-Mail",
"kGeneric_DateOfBirth": "Geburtsdatum",
"kGeneric_VerificationCode": "Verifizierungscode",
"kGeneric_Verify": "Überprüfen",
"kGeneric_Update": "Aktualisieren",
"kGeneric_Logout": "Abmelden",
"kWelcomeModal_Header": "Willkommen zu CollabVM",
"kWelcomeModal_Body": "<p>Bevor Sie fortfahren, machen Sie sich bitte mit unseren Regeln vertraut:</p> <h3>R1. Verbrechen Sie nicht das Gesetz.</h3> Verwenden Sie CollabVM oder das CollabVM-Netzwerk nicht, um das Bundesgesetz der Vereinigten Staaten, das Gesetz des Staates New York oder internationales Recht zu verletzen. Wenn CollabVM erfährt, dass eine Straftat durch seinen Dienst begangen wurde, werden Sie sofort gesperrt und Ihre Aktivitäten können den Behörden gemeldet werden, falls erforderlich.<br/> CollabVM ist gesetzlich verpflichtet, die Strafverfolgungsbehörden zu benachrichtigen, wenn es Kenntnis vom Vorhandensein von Kinderpornographie in seinem Netzwerk oder deren Übertragung erhält.<br/> COPPA wird auch durchgesetzt, bitte benutzen Sie CollabVM nicht, wenn Sie unter 13 Jahre alt sind. <h3>R2. Keine DoS/DDoS-Tools.</h3> Benutzen Sie CollabVM nicht, um DoS/DDoS gegen eine Einzelperson, ein Geschäft, ein Unternehmen oder eine andere Person zu betreiben.<h3>R3. Kein Spam-Versand.</h3> Verwenden Sie diesen Dienst nicht zum Versenden von Spam-E-Mails oder zum Versenden von Spam im Allgemeinen.<h3>R4. Keinen Missbrauch von Exploits.</h3> Missbrauche keine Exploits. Wenn Sie jemanden sehen, der Exploits missbraucht, oder wenn Sie einen Exploit melden möchtest, kontaktiere mich bitte unter: computernewbab@gmail.com <h3>R5. Geben Sie sich nicht als andere Benutzer aus.</h3> Geben Sie sich nicht als andere Mitglieder von CollabVM aus. Wenn Sie erwischt werden, werden Sie vorübergehend von der Verbindung getrennt und gegebenenfalls gesperrt. <h3>R6. Eine Stimme pro Person.</h3> Verwenden Sie keine Methoden oder Hilfsmittel, um die Abstimmungsbeschränkung zu umgehen. Es ist nur eine Stimme pro Person erlaubt, egal wie. Jeder, der dabei erwischt wird, wird gebannt. <h3>R7. Keine Fernadministrations-Tools.</h3> Es dürfen keine Fernadministrations-Tools verwendet werden (z.B. DarkComet, NanoCore, Anydesk, TeamViewer, Orcus, uzw.)<h3>R8. Kein Umgehen von CollabNet</h3> Versuchen Sie nicht, die von CollabNet bereitgestellten Sperren zu umgehen, insbesondere dann nicht, wenn sie dazu benutzt werden, Regel 1, Regel 2 oder Regel 7 zu brechen (oder dumme, übermäßige Dinge auszuführen).<h3>R9. Keine ständigen destruktiven Aktionen durchführen.</h3> Jeder Nutzer darf die VM nicht zerstören (was es ständig unbrauchbar macht), ein anderes Betriebssystem installieren oder das Betriebssystem neu installieren (außer auf VM7 oder VM8) oder Bots ausführen, die dies tun. Dies schließt Bots ein, die massive Mengen an Tastatur-/Mauseingaben spammen (so genanntes \"Kitting\"). <h3>R10. Kein Cryptomining</h3> Der Versuch, auf den VMs Kryptowährungen zu \"schürfen\", führt zu einem Kick und dann zu einem permanenten Bann, wenn Sie es weiter versuchen. Außerdem ist es ja nicht so, dass Sie damit Geld verdienen würden.<h3>NSFW-Warnung</h3> Bitte beachten Sie, dass NSFW-Inhalte auf unserer Anarcho-VM (VM0b0t) erlaubt sind und regelmäßig angesehen werden. Obwohl wir uns bemühen, NSFW von den Haupt-VMs fernzuhalten, kann es vorkommen, dass was durchrutscht. </div>",
"kSiteButtons_Home": "Hauptseite",
"kSiteButtons_FAQ": "FAQ",
"kSiteButtons_Rules": "Regeln",
"kSiteButtons_DarkMode": "Dunkelmodus",
"kSiteButtons_LightMode": "Heller Modus",
"kSiteButtons_Languages": "Sprachen",
"kVM_UsersOnlineText": "Nutzer online:",
"kVM_TurnTimeTimer": "Ihre Zeit läuft in {0} Sekunden aus.",
"kVM_WaitingTurnTimer": "In der Reihe warten für {0} Sekunden.",
"kVM_VoteCooldownTimer": "Bitte warten Sie {0} Sekunden bevor Sie noch eine Abstimmung starten.",
"kVM_VoteForResetTitle": "Möchten Sie die VM zurücksetzen?",
"kVM_VoteForResetTimer": "Abstimmung endet in {0} Sekunden",
"kVMButtons_TakeTurn": "In Reihe stellen.",
"kVMButtons_EndTurn": "Aus der Reihe kommen",
"kVMButtons_ChangeUsername": "Nutzername ändern",
"kVMButtons_Keyboard": "Tastatur",
"KVMButtons_CtrlAltDel": "Strg+Alt+Entf",
"kVMButtons_VoteForReset": "Für Zurücksetzung abstimmen",
"kVMButtons_Screenshot": "Screenshot",
"kQEMUMonitor": "QEMU-Konsole",
"kAdminVMButtons_PassVote": "Abstimmung abschließen",
"kAdminVMButtons_CancelVote": "Abstimmung abbrechen",
"kAdminVMButtons_Restore": "Wiederherstellen",
"kAdminVMButtons_Reboot": "Neustarten",
"kAdminVMButtons_ClearTurnQueue": "Warteschlange leeren",
"kAdminVMButtons_BypassTurn": "Reihe überspringen",
"kAdminVMButtons_IndefiniteTurn": "Unbegrenzter Zeit",
"kAdminVMButtons_Ban": "Sperren",
"kAdminVMButtons_Kick": "Kick",
"kAdminVMButtons_TempMute": "Temporäre Stummschaltung",
"kAdminVMButtons_IndefMute": "Dauerhafte Stummschaltung",
"kAdminVMButtons_Unmute": "Entstummen",
"kAdminVMButtons_GetIP": "IP-Adresse abrufen",
"kVMPrompts_AdminChangeUsernamePrompt": "Geben Sie einen neuen Benutzernamen für {0} ein:",
"kVMPrompts_AdminRestoreVMPrompt": "Sind Sie sicher, dass Sie die virtuelle Maschine wiederherstellen möchten?",
"kVMPrompts_EnterNewUsernamePrompt": "Geben Sie Ihren neuen Nutzername ein.",
"kError_UnexpectedDisconnection": "Sie wurden vom Server getrennt.",
"kError_UsernameTaken": "Dieser Benutzername ist bereits vergeben.",
"kError_UsernameInvalid": "Benutzernamen dürfen nur Zahlen, Buchstaben, Leerzeichen, Bindestriche, Unterstriche und Punkte enthalten und müssen zwischen 3 und 20 Zeichen lang sein.",
"kError_UsernameBlacklisted": "Dieser Benutzername ist verboten.",
"kError_IncorrectPassword": "Falsches Passwort.",
"kAccountModal_Verify": "E-Mail Adresse verifizieren",
"kAccountModal_AccountSettings": "Kontoeinstellungen",
"kAccountModal_ResetPassword": "Passwort zurücksetzen",
"kAccountModal_NewPassword": "Neues Passwort",
"kAccountModal_ConfirmNewPassword": "Neues Passwort bestätigen",
"kAccountModal_CurrentPassword": "Aktuelles Passwort",
"kAccountModal_ConfirmPassword": "Passwort bestätigen",
"kMissingCaptcha": "Bitte füllen Sie das Captcha aus.",
"kPasswordsMustMatch": "Die Passwörter müssen übereinstimmen.",
"kAccountModal_VerifyText": "Wir haben eine E-Mail an {0} verschickt. Um Ihr Konto zu verifizieren, geben Sie bitte den 8-stelligen Code aus der E-Mail unten ein.",
"kAccountModal_VerifyPasswordResetText": "Wir haben eine E-Mail an {0} verschickt. Um Ihr Passwort zurückzusetzen, geben Sie bitte den 8-stelligen Code aus der E-Mail unten ein.",
"kAccountModal_PasswordResetSuccess": "Ihr Passwort wurde erfolgreich geändert. Sie können sich jetzt mit Ihrem neuen Passwort anmelden.",
"kNotLoggedIn": "Nicht angemeldet"
}
}

98
static/lang/fr-fr.json Normal file
View File

@ -0,0 +1,98 @@
{
"languageName": "Français (FR)",
"translatedLanguageName": "French (FR)",
"flag": "🇫🇷",
"author": "pikterra",
"stringKeys": {
"kGeneric_CollabVM": "CollabVM",
"kGeneric_Yes": "Oui",
"kGeneric_No": "Non",
"kGeneric_Ok": "OK",
"kGeneric_Cancel": "Annuler",
"kGeneric_Send": "Envoyer",
"kGeneric_Understood": "Compris",
"kGeneric_Username": "Nom d'utilisateur",
"kGeneric_Password": "Mot de passe",
"kGeneric_Login": "Connection",
"kGeneric_Register": "Inscription",
"kGeneric_EMail": "E-Mail",
"kGeneric_DateOfBirth": "Date de naissance",
"kGeneric_VerificationCode": "Code de Vérification",
"kGeneric_Verify": "Verifier",
"kGeneric_Update": "Mise à jour",
"kGeneric_Logout": "Déconnection",
"kWelcomeModal_Header": "Bienvenue sur CollabVM",
"kWelcomeModal_Body": "<p>Avant de continuer, veuillez vous familiariser avec nos règles:</p> <h3>R1. Respecter la Loi.</h3> N'utilisez pas le réseau CollabVM pour violez les lois fédéral des Etats-Unis, lois de New-York, ou les lois International. Si CollabVM trouve qu'un crime a été commis vous allez etre immédiatement bannis, et vos activités peuvent être signaler aux authorités si nécessaire.<br><br>CollabVM se vera de notifier des agences d'enforcement des lois si il trouve de la présence de pédo-pornographie sur ou étant transmis par le réseau.<br><br>Les lois COPPA sont aussi misent en place, n'utilisez pas CollabVM si vous avez moins de 13 ans. <h3>R2. N'utilisez pas d'outils de DoS/DDoS.</h3> N'utilisez pas CollabVM pour Dos/DDoS un individu, un business, une entreprise ou n'importe qui d'autre. <h3>R3. Pas de spam.</h3> Ne spammez pas d'email à l'aide de ce service. <h3>R4. N'abusez pas d'exploits.</h3> N'abusez pas d'exploits, et si vous voyez quelq'un abusez d'exploits ou que vous avez besoin d'en signaler un, veuillez me contacter à : computernewbab@gmail.com <h3>R5. N'usurpez pas l'identité d'autres utilisateurs.</h3> N'usurpez pas d'autres membres de CollabVM. Si vous êtes pris sur le fait vous allez être temporairement déconnecté, et bannis si nécessaire. <h3>R6. Un seul vote par personne.</h3> N'utilisez pas de méthodes ou d'outils pour bypasser les restrictions du système de votes. Un seul vote par personne est autorisé, peu importe quoi. N'importe qui trouvé a faire cela sera bannis. <h3>R7. Pas d'outils d'accès a distance.</h3> N'utilisez pas d'outils d'accès a distance (ex: DarkComet, NanoCore, Anydesk, TeamViewer, Orcus, etc.) <h3>R8. Ne bypasser pas CollabNet.</h3> N'éssayer pas de bypasser le bloquage introduis par CollabNet, surtout si ces pour briser les régles 1, 2 et 7 (ou utiliser des choses trop utilisés). <h3>R9. Ne faites pas d'actions destructives constamment.</h3> Les utilisateurs ne doivent pas détruire un VM (le rendant inutilisable constamment), installer/réinstaller le système d'exploitation (a part sur VM7 et sur VM8), ou faire des bots qui le font. Cela inclus aussi les bots qui spam le clavier et la souris (\"kitting\"). <h3>R10. Pas de minage de cryptomonnaie</h3> Vous allez vous faire exclure si vous tentez de miner de la cryptomonnaie sur un des VMs, puis un ban permanent si vous persister. Mais de toute façon ces pas comme si vous allez vous faire de l'argent comme ça. <h3>Attention NSFW</h3> Attention veuillez noter que le contenu NSFW est autorisé sur le VM anarchie (VM0b0t), et est vue réguilièrement. De plus, nous faisons des efforts pour tenir le contenu NSFW hors des VMs général, mais des utilisateurs arrivent quand même parfois à en montrer.",
"kSiteButtons_Home": "Menu",
"kSiteButtons_FAQ": "FAQ",
"kSiteButtons_Rules": "Règles",
"kSiteButtons_DarkMode": "Mode sombre",
"kSiteButtons_LightMode": "Mode clair",
"kSiteButtons_Languages": "Languages",
"kVM_UsersOnlineText": "Utilisateurs en ligne:",
"kVM_TurnTimeTimer": "Vôtre tour se termine dans {0} secondes.",
"kVM_WaitingTurnTimer": "Vôtre tour sera dans {0} secondes.",
"kVM_VoteCooldownTimer": "Veuillez attendre {0} secondes avant de commencer un autre vote.",
"kVM_VoteForResetTitle": "Voulez vous réinitialiser le VM ?",
"kVM_VoteForResetTimer": "Le vote se termine dans {0} secondes",
"kVMButtons_TakeTurn": "Commencer vôtre tour",
"kVMButtons_EndTurn": "Terminer vôtre tour",
"kVMButtons_ChangeUsername": "Changer de nom d'utilisateur",
"kVMButtons_Keyboard": "Clavier",
"KVMButtons_CtrlAltDel": "Ctrl+Alt+Del",
"kVMButtons_VoteForReset": "Commencer un vote pour reset",
"kVMButtons_Screenshot": "Capture d'écran",
"kQEMUMonitor": "Moniteur QEMU",
"kAdminVMButtons_PassVote": "Passer le vote",
"kAdminVMButtons_CancelVote": "Annuler le vote",
"kAdminVMButtons_Restore": "Rétablir",
"kAdminVMButtons_Reboot": "Redémarrer",
"kAdminVMButtons_ClearTurnQueue": "Supprimer la queue pour un tour",
"kAdminVMButtons_BypassTurn": "Bypasser vôtre tour",
"kAdminVMButtons_IndefiniteTurn": "Tour indéfinis",
"kAdminVMButtons_Ban": "Ban",
"kAdminVMButtons_Kick": "Exclusion",
"kAdminVMButtons_TempMute": "Mute temporaire",
"kAdminVMButtons_IndefMute": "Mute indéfinis",
"kAdminVMButtons_Unmute": "Unmute",
"kAdminVMButtons_GetIP": "Trouver l'IP",
"kVMPrompts_AdminChangeUsernamePrompt": "Entrer un nouveau nom d'utilisateur pour {0}:",
"kVMPrompts_AdminRestoreVMPrompt": "Êtes-vous sûr de rétablir le VM?",
"kVMPrompts_EnterNewUsernamePrompt": "Entrer un nouveau nom d'utilisateur, ou laisser l'espace vide pour etre assigner un nom d'utilisateur invité",
"kError_UnexpectedDisconnection": "Vous avez été déconnecté du serveur.",
"kError_UsernameTaken": "Ce nom d'utilisateur est déjà pris",
"kError_UsernameInvalid": "Les noms d'utilisateurs ne peuvent que contenirs des chiffres, lettres, éspaces, tirets, tirets du bas, et des points, et ils doivent êtres d'une longueur entre 3 et 20.",
"kError_UsernameBlacklisted": "Ce nom d'utilisateur est interdit.",
"kError_IncorrectPassword": "Mot de passe incorrect.",
"kAccountModal_Verify": "Vérifier l'E-mail",
"kAccountModal_AccountSettings": "Paramètres de compte",
"kAccountModal_ResetPassword": "Réinitialiser le Mot de passe",
"kAccountModal_NewPassword": "Nouveau Mot de passe",
"kAccountModal_ConfirmNewPassword": "Confirmer le nouveau Mot de passe",
"kAccountModal_CurrentPassword": "Mot de passe actuel",
"kAccountModal_ConfirmPassword": "Confirmer le nouveau Mot de passe",
"kMissingCaptcha": "Veuillez compléter ce Captcha.",
"kPasswordsMustMatch": "Les Mot de passes doivent se corréspondre.",
"kAccountModal_VerifyText": "Nous avons envoyez un E-mail à {0}. Pour vérifier votre compte, veuillez entrer le mot de passe à 8 chiffre envoyé par E-mail.",
"kAccountModal_VerifyPasswordResetText": "Nous avons envoyez un E-mail à {0}. Pour réinitialiser votre Mot de passe, veuillez entrer le mot de passe à 8 chiffre envoyé par E-mail.",
"kAccountModal_PasswordResetSuccess": "Vôtre Mot de passe à été réinitialiser avec succès. Vous pouvez maintenant vous connecter avec votre nouveau Mot de passe.",
"kNotLoggedIn": "Non connecté"
}
}

98
static/lang/pl-pl.json Normal file
View File

@ -0,0 +1,98 @@
{
"languageName": "Polski",
"translatedLanguageName": "Polish",
"flag": "🇵🇱",
"author": "Mattx",
"stringKeys": {
"kGeneric_CollabVM": "CollabVM",
"kGeneric_Yes": "Tak",
"kGeneric_No": "Nie",
"kGeneric_Ok": "TODO OK",
"kGeneric_Cancel": "TODO Cancel",
"kGeneric_Send": "TODO Send",
"kGeneric_Understood": "Zrozumiane",
"kGeneric_Username": "TODO Username",
"kGeneric_Password": "TODO Password",
"kGeneric_Login": "TODO Log in",
"kGeneric_Register": "TODO Register",
"kGeneric_EMail": "TODO E-Mail",
"kGeneric_DateOfBirth": "TODO Date of Birth",
"kGeneric_VerificationCode": "TODO Verification Code",
"kGeneric_Verify": "TODO Verify",
"kGeneric_Update": "TODO Update",
"kGeneric_Logout": "TODO Log out",
"kWelcomeModal_Header": "Witamy na CollabVM.",
"kWelcomeModal_Body": "<p>Zanim rozpoczniesz, prosimy o przeczytanie regulaminu:</p> <h3>R1. Nie łam prawa.</h3> Nie korzystaj z CollabVM czy sieci CollabVM aby łamać prawo federalne w Stanach Zjednoczonych, prawo stanu w Nowym Jorku czy międzynarodowych praw. W razie, że CollabVM dowie się o przestępstwie popełnionym za pośrednictwem jego usług, twój dostęp zostanie zablokowany i twoja działalność może być w razie potrzeby zgłoszona władzom.<br><br>CollabVM jest zobowiązany prawnie do zawiadomienia organów ścigania jeśli dowie się o obecności pornografii dziecięcej na, lub transmitowanej przez jego sieć.<br><br>Akt COPPA jest także egzekwowany, prosimy o nie korzystanie z CollabVM jeśli nie ukończyłeś 13 lat. <h3>R2. Zakaz narzędzi DoS/DDoS.</h3> Nie używaj CollabVM aby wykonywać ataki DoS/DDoS na osoby prywatne, działalności, firmy czy na kogokolwiek innego. <h3>R3. Zakaz rozpowszechniania spamu.</h3>Nie spamuj żadnych emaili korzystając z tej usługi, ani nie wysyłaj żadnego innego rodzaju spamu. <h3>R4. Nie nadużywaj exploitów.</h3> Nie używaj żadnych exploitów, w przypadku gdy zobaczysz że ktoś je wykorzystuje lub potrzebujesz zgłosić exploit, proszę o kontakt na emailu: computernewbab@gmail.com <h3>R5. Nie podszywaj się pod innych.</h3> Nie podszywaj się pod innych użytkowników CollabVM. Jeśli zostaniesz złapany, zostaniesz tymczasowo odłączony i zbanowany w razie potrzeby. <h3>R6. Jeden głos na osobę.</h3> Nie wykorzystuj żadnych metod lub narzędzi aby obejść ograniczenie na głosach. Tylko jeden głos na osobę jest zezwolony, niezależnie od sytuacji. Każdy, kto jest przyłapany na obchodzenie głosów zostanie natychmiast zbanowany. <h3>R7. Zakaz narzędzi zdalnej kontroli/administracji i narzędzi typu RAT</h3> Nie korzystaj z narzędzi zdalnej administracji (przykładowo: DarkComet, NanoCore, AnyDesk, TeamViewer, Orcus, itp.) <h3>R8. Zakaz obchodzenia systemu CollabNet.</h3> Nie próbuj obejść blokad zapewnionych przez CollabNet, zwłaszcza jeśli jest to aby łamać zasady R1, R2 lub R7 (albo żeby uruchamiać głupie, nadużyte rzeczy). <h3>R9. Nie wykonuj stale działań niszczących.</h3> Żaden użytkownik nie może stale niszczyć wirtualnej maszyny (co powoduje, że wirtualna maszyna jest stale niemożliwa do wykorzystania), instalować/ponownie instalować systemu operacyjnego (oprócz na wirtualnych maszynach VM7 i VM8), ani uruchamiać boty, które wykonują takie czynności. Ta zasada też obejmuje boty, które wysyłają dużą ilość losowych wejść klawiatury/myszki (często nazywane \"kitting\"). <h3>R10. Zakaz kopania kryptowalut.</h3> Wszystkie próby kopania kryptowalut na wirtualnych maszynach będzie skutkować wyrzuceniem, a potem stałym banem jeśli będziesz próbować dalej. I tak nawet nie zrobiłbyś żadnych pieniędzy z robienia tego. <h3>Uwaga o nieodpowiednich treściach</h3> Proszę o zwrócenie uwagi na to, że nieodpowiednie treści są zezwolone na naszej anarchicznej maszynie wirtualnej (VM0b0t) i są wyświetlane regularnie. W dodatku, wkładamy wysiłek w zapobieganiu wyświetlania nieodpowiednich treści na naszych głównych wirtualnych maszynach, czasami użytkownicy mogą prześlizgnąć je.",
"kSiteButtons_Home": "Strona domowa",
"kSiteButtons_FAQ": "FAQ",
"kSiteButtons_Rules": "Regulamin",
"kSiteButtons_DarkMode": "TODO Dark Mode",
"kSiteButtons_LightMode": "TODO Light Mode",
"kSiteButtons_Languages": "TODO Languages",
"kVM_UsersOnlineText": "Użytkownicy online:",
"kVM_TurnTimeTimer": "Kolejka wygasa za {0} sekund.",
"kVM_WaitingTurnTimer": "Czekanie na kolejkę za {0} sekund.",
"kVM_VoteCooldownTimer": "Prosimy zaczekać {0} sekund przed rozpoczęciem następnego głosowania.",
"kVM_VoteForResetTitle": "Czy chcesz zresetować wirtualną maszynę?",
"kVM_VoteForResetTimer": "Głosowanie kończy się za {0} sekund.",
"kVMButtons_TakeTurn": "Weź kolej",
"kVMButtons_EndTurn": "Zakończ kolej",
"kVMButtons_ChangeUsername": "Zmień nazwę użytkownika",
"kVMButtons_Keyboard": "TODO Keyboard",
"KVMButtons_CtrlAltDel": "TODO Ctrl+Alt+Del",
"kVMButtons_VoteForReset": "Zagłosuj o reset",
"kVMButtons_Screenshot": "Zrzut ekranu",
"kQEMUMonitor": "TODO QEMU Monitor",
"kAdminVMButtons_PassVote": "TODO Pass Vote",
"kAdminVMButtons_CancelVote": "TODO Cancel Vote",
"kAdminVMButtons_Restore": "TODO Restore",
"kAdminVMButtons_Reboot": "TODO Reboot",
"kAdminVMButtons_ClearTurnQueue": "TODO Clear Turn Queue",
"kAdminVMButtons_BypassTurn": "TODO Bypass Turn",
"kAdminVMButtons_IndefiniteTurn": "TODO Indefinite Turn",
"kAdminVMButtons_Ban": "TODO Ban",
"kAdminVMButtons_Kick": "TODO Kick",
"kAdminVMButtons_TempMute": "TODO Temporary Mute",
"kAdminVMButtons_IndefMute": "TODO Indefinite Mute",
"kAdminVMButtons_Unmute": "TODO Unmute",
"kAdminVMButtons_GetIP": "TODO Get IP",
"kVMPrompts_AdminChangeUsernamePrompt": "TODO Enter new username for {0}:",
"kVMPrompts_AdminRestoreVMPrompt": "TODO Are you sure you want to restore the VM?",
"kVMPrompts_EnterNewUsernamePrompt": "Wpisz nową nazwę użytkownika",
"kError_UnexpectedDisconnection": "TODO You have been disconnected from the server.",
"kError_UsernameTaken": "TODO That username is already taken",
"kError_UsernameInvalid": "TODO Usernames can contain only numbers, letters, spaces, dashes, underscores, and dots, and it must be between 3 and 20 characters.",
"kError_UsernameBlacklisted": "TODO That username has been blacklisted.",
"kError_IncorrectPassword": "TODO Incorrect password.",
"kAccountModal_Verify": "TODO Verify E-Mail",
"kAccountModal_AccountSettings": "TODO Account Settings",
"kAccountModal_ResetPassword": "TODO Reset Password",
"kAccountModal_NewPassword": "TODO New Password",
"kAccountModal_ConfirmNewPassword": "TODO Confirm New Password",
"kAccountModal_CurrentPassword": "TODO Current Password",
"kAccountModal_ConfirmPassword": "TODO Confirm Password",
"kMissingCaptcha": "TODO Please fill out the captcha.",
"kPasswordsMustMatch": "TODO Passwords must match.",
"kAccountModal_VerifyText": "TODO We sent an E-Mail to {0}. To verify your account, please enter the 8-digit code from the E-Mail below.",
"kAccountModal_VerifyPasswordResetText": "TODO We sent an E-Mail to {0}. To reset your password, please enter the 8-digit code from the E-Mail below.",
"kAccountModal_PasswordResetSuccess": "TODO Your password has been changed successfully. You can now log in with your new password.",
"kNotLoggedIn": "TODO Not Logged in"
}
}