diff --git a/app/locale/de-CH.coffee b/app/locale/de-CH.coffee index 54294dc50..ef768b6d7 100644 --- a/app/locale/de-CH.coffee +++ b/app/locale/de-CH.coffee @@ -1,6 +1,6 @@ -module.exports = nativeDescription: "Deutsch (Schweiz)", englishDescription: "German (Switzerland)", translation: +module.exports = nativeDescription: "Dütsch (Schwiiz)", englishDescription: "German (Switzerland)", translation: home: - slogan: "Lern, wiemer JavaScript programmiert, indem du es Spiel spielsch!" + slogan: "Lern, wiemer JavaScript programmiert, indem du spielsch!" no_ie: "CodeCombat funktioniert uf InternetExplorer 8 und älter nid. Sorry!" # Warning that only shows up in IE8 and older no_mobile: "CodeCombat isch nid für mobili Grät entwicklet worde und funktioniert vilicht nid!" # Warning that shows up on mobile devices play: "Spiele" # The big play button that opens up the campaign view. @@ -56,28 +56,28 @@ module.exports = nativeDescription: "Deutsch (Schweiz)", englishDescription: "Ge unlock: "Freischalte" # For purchasing items and heroes confirm: "Bestätige" owned: "Scho gkauft" # For items you own - locked: "Nonig freischaltbar" -# purchasable: "Purchasable" # For a hero you unlocked but haven't purchased + locked: "Nonig kauft" + purchasable: "kaufen" # For a hero you unlocked but haven't purchased available: "vorhandä" -# skills_granted: "Skills Granted" # Property documentation details + skills_granted: "Fähigkeite" # Property documentation details heroes: "Helde" # Tooltip on hero shop button from /play - achievements: "Achievements" # Tooltip on achievement list button from /play + achievements: "Erfolg" # Tooltip on achievement list button from /play account: "Account" # Tooltip on account button from /play settings: "Istellige" # Tooltip on settings button from /play -# poll: "Poll" # Tooltip on poll button from /play + poll: "Pool" # Tooltip on poll button from /play next: "Wiiter" # Go from choose hero to choose inventory before playing a level change_hero: "Held wächsle" # Go back from choose inventory to choose hero -# choose_inventory: "Equip Items" -# buy_gems: "Buy Gems" -# subscription_required: "Subscription Required" + choose_inventory: "Items uusrüschte" + buy_gems: "Edelstei chaufä" + subscription_required: "Abonnement benötigt" older_campaigns: "Älteri Kampagne" anonymous: "Anonyme Spieler" level_difficulty: "Schwierigkeit: " campaign_beginner: "Afängerkampagne" -# awaiting_levels_adventurer_prefix: "We release five levels per week." -# awaiting_levels_adventurer: "Sign up as an Adventurer" -# awaiting_levels_adventurer_suffix: "to be the first to play new levels." -# adjust_volume: "Adjust volume" + awaiting_levels_adventurer_prefix: "Mier möched 5 Levels pro Wuche" + awaiting_levels_adventurer: "Mäld dich a as en Abendtüürer" + awaiting_levels_adventurer_suffix: "um de erscht zii vo die neue Levels spiilt" + adjust_volume: "Luutsterchi apasse" choose_your_level: "Wähl dis Level us" # The rest of this section is the old play view at /play-old and isn't very important. adventurer_prefix: "Du chasch zu de untere Level zrugg goh oder die kommende Level diskutiere im " adventurer_forum: "Abentürer-Forum" @@ -90,16 +90,16 @@ module.exports = nativeDescription: "Deutsch (Schweiz)", englishDescription: "Ge campaign_multiplayer_description: "... i dene du Chopf a Chopf geg anderi Spieler spielsch." campaign_player_created: "Vo Spieler erstellti Level" campaign_player_created_description: "... i dene du gege d Kreativität vome Handwerker Zauberer kämpfsch." -# campaign_classic_algorithms: "Classic Algorithms" -# campaign_classic_algorithms_description: "... in which you learn the most popular algorithms in Computer Science." + campaign_classic_algorithms: "Klassischi Algorithme" + campaign_classic_algorithms_description: "... wo du die beliebtischte Algorithmue vode Computer Welt lernsch.." share_progress_modal: blurb: "Du machsch grossi Fortschritts! Verzells öperem wieviel du glernt häsch mit CodeCombat." email_invalid: "Email Adrässä isch falsch." -# form_blurb: "Enter your parent's email below and we’ll show them!" + form_blurb: "Gib bitte dEmail Adrässe vo dine Eltere aa" form_label: "Email Adrässä" placeholder: "Email Adrässä" -# title: "Excellent Work, Apprentice" + title: "Gueti Arbeit!" login: sign_up: "Account erstelle" @@ -107,8 +107,8 @@ module.exports = nativeDescription: "Deutsch (Schweiz)", englishDescription: "Ge logging_in: "Am Ilogge" log_out: "Uslogge" forgot_password: "Passwort vergässe?" -# authenticate_gplus: "Authenticate G+" -# load_profile: "Load G+ Profile" + authenticate_gplus: "Mit G+ audentifiziere" + load_profile: "G+ Profil ladä" finishing: "Fertigstelle" sign_in_with_facebook: "Mit Facebook aamelde" sign_in_with_gplus: "Mit G+ aamelde" @@ -125,20 +125,20 @@ module.exports = nativeDescription: "Deutsch (Schweiz)", englishDescription: "Ge recover: recover_account_title: "Account wiederherstelle" - send_password: "Recovery Password sende" -# recovery_sent: "Recovery email sent." + send_password: "Widerherstelligs Passwort sende" + recovery_sent: "Widerherstelligs Passwort isch gsendet" items: -# primary: "Primary" -# secondary: "Secondary" -# armor: "Armor" -# accessories: "Accessories" + primary: "Primär" + secondary: "Sekundär" + armor: "Rüschtig" + accessories: "Accessories" misc: "Diverses" books: "Büecher" common: -# back: "Back" # When used as an action verb, like "Navigate backward" -# continue: "Continue" # When used as an action verb, like "Continue forward" + back: "Zrugg" # When used as an action verb, like "Navigate backward" + continue: "Wiiterfare" # When used as an action verb, like "Continue forward" loading: "Lade..." saving: "Speichere..." sending: "Sende..." @@ -151,36 +151,36 @@ module.exports = nativeDescription: "Deutsch (Schweiz)", englishDescription: "Ge # fork: "Fork" play: "Spiele" # When used as an action verb, like "Play next level" retry: "nomol versuche" -# actions: "Actions" + actions: "Aktione" info: "Info" help: "Hilf" -# watch: "Watch" -# unwatch: "Unwatch" + watch: "Aluege" + unwatch: "Nüm Aluege" submit_patch: "Patch ireiche" -# submit_changes: "Submit Changes" + submit_changes: "Wechsel ireiche" general: and: "und" name: "Name" date: "Datum" -# body: "Body" + body: "Body" version: "Version" -# pending: "Pending" -# accepted: "Accepted" -# rejected: "Rejected" -# withdrawn: "Withdrawn" -# submitter: "Submitter" -# submitted: "Submitted" -# commit_msg: "Commit Message" -# review: "Review" + pending: "in Bearbeitig" + accepted: "Akzeptiert" + rejected: "Nid akzeptiert" + withdrawn: "Zruggzie" + submitter: "Sender" + submitted: "Gesendet" + commit_msg: "Nachricht abschicke" + review: "Review" version_history: "Versionsverlauf" -# version_history_for: "Version History for: " -# select_changes: "Select two changes below to see the difference." -# undo_prefix: "Undo" -# undo_shortcut: "(Ctrl+Z)" -# redo_prefix: "Redo" -# redo_shortcut: "(Ctrl+Shift+Z)" -# play_preview: "Play preview of current level" + version_history_for: "Versionsverlauf für: " + select_changes: "Wähl zwei Verändrige um unne Ihre Unterschid zgse." + undo_prefix: "Eis zrugg" + undo_shortcut: "(Ctrl+Z)" + redo_prefix: "Nomal mache" + redo_shortcut: "(Ctrl+Shift+Z)" + play_preview: "Spiel dPreview vom aktuelle Level" result: "Resultat" results: "Resultat" description: "Beschriibig" @@ -204,7 +204,7 @@ module.exports = nativeDescription: "Deutsch (Schweiz)", englishDescription: "Ge player: "Spieler" player_level: "Stufe" # Like player level 5, not like level: Dungeons of Kithgard warrior: "Krieger" -# ranger: "Ranger" + ranger: "Ranger" wizard: "Zauberer" units: @@ -247,7 +247,7 @@ module.exports = nativeDescription: "Deutsch (Schweiz)", englishDescription: "Ge reload_really: "Bisch sicher du willsch level neu lade bis zrugg zum Afang?" reload_confirm: "Alles neu lade" victory: "Gwunne" -# victory_title_prefix: "" + victory_title_prefix: "" victory_title_suffix: " Vollständig" victory_sign_up: "Meld dich ah zum din Fortschritt speichere" victory_sign_up_poke: "Wötsch din Code speichere? Erstell gratis en Account!" @@ -259,21 +259,21 @@ module.exports = nativeDescription: "Deutsch (Schweiz)", englishDescription: "Ge victory_review: "Verzell üs meh!" # Only in old-style levels. victory_hour_of_code_done: "Bisch fertig?" victory_hour_of_code_done_yes: "Jo, ich bin fertig mit mim Hour of Code™!" -# victory_experience_gained: "XP Gained" -# victory_gems_gained: "Gems Gained" -# victory_viking_code_school: "Holy smokes, that was a hard level you just beat! If you aren't already a software developer, you should be. You just got fast-tracked for acceptance with Viking Code School, where you can take your skills to the next level and become a professional web developer in 14 weeks." -# victory_become_a_viking: "Become a Viking" + victory_experience_gained: "Erfarig bechoo" + victory_gems_gained: "Edelstei bechoo" + victory_viking_code_school: "Oh mein Gott, dass isch aber es stregs Level gsi und du heschs gschafft! Also wen du nu kei Software-Entwickler bisch, sötsch eine sii! Du hesch en Iiladig becho um at Viking Code Schuel zgha wodu dini Fähigkeite chasch wiiterentwickle und en professionele Entwickel in nur 14 Täg werde!" + victory_become_a_viking: "Werd en Vikinger!" guide_title: "Handbuech" tome_minion_spells: "Zaubersprüch vo dine Minions" # Only in old-style levels. tome_read_only_spells: "Read-Only Zaubersprüch" # Only in old-style levels. tome_other_units: "Anderi Einheite" # Only in old-style levels. -# tome_cast_button_run: "Run" -# tome_cast_button_running: "Running" -# tome_cast_button_ran: "Ran" -# tome_submit_button: "Submit" -# tome_reload_method: "Reload original code for this method" # Title text for individual method reload button. + tome_cast_button_run: "Renn" + tome_cast_button_running: "Renne" + tome_cast_button_ran: "grennt" + tome_submit_button: "Abschicke" + tome_reload_method: "Lad de Orginal Code für die Methode" # Title text for individual method reload button. tome_select_method: "Wähl a Methodä" -# tome_see_all_methods: "See all methods you can edit" # Title text for method list selector (shown when there are multiple programmable methdos). + tome_see_all_methods: "Lueg alli Methode a wot chasch bearbeite" # Title text for method list selector (shown when there are multiple programmable methdos). tome_select_a_thang: "Wähl öpper us für" tome_available_spells: "Verfüegbari Zaubersprüch" tome_your_skills: "Dini Fähigkaitä" @@ -321,153 +321,153 @@ module.exports = nativeDescription: "Deutsch (Schweiz)", englishDescription: "Ge tip_hardware_problem: "F: Wie viel Programmierer bruuchts zum e Glüehbire uswechsle? A: Keine, da isch es Hardware Problem." # tip_hofstadters_law: "Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law." # tip_premature_optimization: "Premature optimization is the root of all evil. - Donald Knuth" -# tip_brute_force: "When in doubt, use brute force. - Ken Thompson" + tip_brute_force: "Went am verzwifle bisch, bruch brute force. - Ken Thompson" # tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..." -# tip_superpower: "Coding is the closest thing we have to a superpower." + tip_superpower: "Coding isch snöchte wo mier hend was ane Superchraaft ane chund!" # tip_control_destiny: "In real open source, you have the right to control your own destiny. - Linus Torvalds" -# tip_no_code: "No code is faster than no code." + tip_no_code: "Kei Code isch schneller als kei Code!" # tip_code_never_lies: "Code never lies, comments sometimes do. — Ron Jeffries" # tip_reusable_software: "Before software can be reusable it first has to be usable." # tip_optimization_operator: "Every language has an optimization operator. In most languages that operator is ‘//’" # tip_lines_of_code: "Measuring programming progress by lines of code is like measuring aircraft building progress by weight. — Bill Gates" -# tip_source_code: "I want to change the world but they would not give me the source code." -# tip_javascript_java: "Java is to JavaScript what Car is to Carpet. - Chris Heilmann" -# tip_move_forward: "Whatever you do, keep moving forward. - Martin Luther King Jr." -# tip_google: "Have a problem you can't solve? Google it!" + tip_source_code: "Ich wet dWält verändere aber die wend mier de Source Code nid gää." + tip_javascript_java: "Java isch zu JavaScript wie es Auto zume Automat. - Chris Heilmann" + tip_move_forward: "Was immer du machsch, mach immer me Fortschritt. - Martin Luther King Jr." + tip_google: "Hesch es Problem und chunsch nüm wiiter? Googles doch mal!" # tip_adding_evil: "Adding a pinch of evil." # tip_hate_computers: "That's the thing about people who think they hate computers. What they really hate is lousy programmers. - Larry Niven" -# tip_open_source_contribute: "You can help CodeCombat improve!" + tip_open_source_contribute: "Du chasch helfe CodeCombat zverbessere!" # tip_recurse: "To iterate is human, to recurse divine. - L. Peter Deutsch" game_menu: -# inventory_tab: "Inventory" + inventory_tab: "Inventar" save_load_tab: "Spaicherä/Ladä" options_tab: "Optionä" -# guide_tab: "Guide" -# guide_video_tutorial: "Video Tutorial" + guide_tab: "Guide" + guide_video_tutorial: "Vidio Tutorial" guide_tips: "Tipps" multiplayer_tab: "Multiplayer" -# auth_tab: "Sign Up" -# inventory_caption: "Equip your hero" -# choose_hero_caption: "Choose hero, language" -# save_load_caption: "... and view history" -# options_caption: "Configure settings" + auth_tab: "Regischtriere" + inventory_caption: "Rüscht din Held uus" + choose_hero_caption: "Wähl din Held und dini Sprach" + save_load_caption: "... und lueg dini Gschicht aa." + options_caption: "Iistellige apasse" guide_caption: "Doku und Tipps" -# multiplayer_caption: "Play with friends!" -# auth_caption: "Save your progress." + multiplayer_caption: "Spil mid dini Fründe!" + auth_caption: "Speichere din Fortschritt." -# leaderboard: -# leaderboard: "Leaderboard" -# view_other_solutions: "View Leaderboards" -# scores: "Scores" -# top_players: "Top Players by" -# day: "Today" -# week: "This Week" -# all: "All-Time" -# time: "Time" -# damage_taken: "Damage Taken" -# damage_dealt: "Damage Dealt" -# difficulty: "Difficulty" -# gold_collected: "Gold Collected" + leaderboard: + leaderboard: "Ranglischte" + view_other_solutions: "Lueg der dRanglischte aa!" + scores: "Pünkt" + top_players: "Beschti Speiler" + day: "Hüt" + week: "Die Wuuche" + all: "Vo immer" + time: "Ziit" + damage_taken: "Schade gnoo" + damage_dealt: "Schade uusteilt" + difficulty: "Schwirigkeitsgrad" + gold_collected: "Gold gsammlet" -# inventory: -# choose_inventory: "Equip Items" -# equipped_item: "Equipped" -# required_purchase_title: "Required" -# available_item: "Available" -# restricted_title: "Restricted" -# should_equip: "(double-click to equip)" -# equipped: "(equipped)" -# locked: "(locked)" -# restricted: "(restricted in this level)" -# equip: "Equip" -# unequip: "Unequip" + inventory: + choose_inventory: "Items uusrüschte" + equipped_item: "Uusgrüschteti Items" + required_purchase_title: "Benötigt" + available_item: "Verfüegbar" + restricted_title: "Verbote" + should_equip: "(2mal Klicke zum uusrüschte)" + equipped: "(usgrüschtet)" + locked: "(geschperrt)" + restricted: "(verbote i dem Level)" + equip: "Uusrüschte" + unequip: "Nüm Uusrüschte" -# buy_gems: -# few_gems: "A few gems" -# pile_gems: "Pile of gems" -# chest_gems: "Chest of gems" -# purchasing: "Purchasing..." -# declined: "Your card was declined" -# retrying: "Server error, retrying." -# prompt_title: "Not Enough Gems" -# prompt_body: "Do you want to get more?" -# prompt_button: "Enter Shop" -# recovered: "Previous gems purchase recovered. Please refresh the page." + buy_gems: + few_gems: "Es paar Edelstei" + pile_gems: "En hufe vo Edelstei" + chest_gems: "En ganzi True voll Edelstei" + purchasing: "Kaufen..." + declined: "Dini Charte isch leider abglehnt worde." + retrying: "Server Fehler, probiere nochmals." + prompt_title: "Nid gnug Edelstei!" + prompt_body: "Wetsch mee chaufe?" + prompt_button: "zum Shop" + recovered: "Früenere Ichauf zruggerstatet. Bitte dSite neu lade!" # price: "x3500 / mo" -# subscribe: -# comparison_blurb: "Sharpen your skills with a CodeCombat subscription!" -# feature1: "80+ basic levels across 4 worlds" + subscribe: + comparison_blurb: "Verschärf dins Chönne midme CodeCombat Abonement." + feature1: "80+ basis levels in 4 Weltete!" # feature2: "7 powerful new heroes with unique skills!" -# feature3: "50+ bonus levels" + feature3: "50+ bonus levels" # feature4: "3500 bonus gems every month!" -# feature5: "Video tutorials" -# feature6: "Premium email support" -# free: "Free" -# month: "month" -# subscribe_title: "Subscribe" -# unsubscribe: "Unsubscribe" -# confirm_unsubscribe: "Confirm Unsubscribe" -# never_mind: "Never Mind, I Still Love You" -# thank_you_months_prefix: "Thank you for supporting us these last" -# thank_you_months_suffix: "months." -# thank_you: "Thank you for supporting CodeCombat." -# sorry_to_see_you_go: "Sorry to see you go! Please let us know what we could have done better." -# unsubscribe_feedback_placeholder: "O, what have we done?" -# parent_button: "Ask your parent" -# parent_email_description: "We'll email them so they can buy you a CodeCombat subscription." -# parent_email_input_invalid: "Email address invalid." -# parent_email_input_label: "Parent email address" -# parent_email_input_placeholder: "Enter parent email" -# parent_email_send: "Send Email" -# parent_email_sent: "Email sent!" -# parent_email_title: "What's your parent's email?" -# parents: "For Parents" -# parents_title: "Dear Parent: Your child is learning to code. Will you help them continue?" -# parents_blurb1: "Your child has played __nLevels__ levels and learned programming basics. Help cultivate their interest and buy them a subscription so they can keep playing." -# parents_blurb1a: "Computer programming is an essential skill that your child will undoubtedly use as an adult. By 2020, basic software skills will be needed by 77% of jobs, and software engineers are in high demand across the world. Did you know that Computer Science is the highest-paid university degree?" -# parents_blurb2: "For $9.99 USD/mo, your child will get new challenges every week and personal email support from professional programmers." -# parents_blurb3: "No Risk: 100% money back guarantee, easy 1-click unsubscribe." -# payment_methods: "Payment Methods" -# payment_methods_title: "Accepted Payment Methods" -# payment_methods_blurb1: "We currently accept credit cards and Alipay." + feature5: "Video Aleitige" + feature6: "Premium Email Hilf" + free: "Gratis" + month: "Monät" + subscribe_title: "Aboniere" + unsubscribe: "Deaboniere" + confirm_unsubscribe: "Deaboniere beschtätige" + never_mind: "Keis Problem, ich lieb dich trotzdem." + thank_you_months_prefix: "Danke das du üs die Monät" + thank_you_months_suffix: "so unterschtütz hesch." + thank_you: "Danke, dass du CodeCombat so unterschtüzisch." + sorry_to_see_you_go: "Schad, dass du gasch! Bitte seg üs doch was mier hetted chönne besser mache." + unsubscribe_feedback_placeholder: "Ohaletz, was hemmer gmacht?" + parent_button: "Frag dini Eltere" + parent_email_description: "We'll email them so they can buy you a CodeCombat subscription." + parent_email_input_invalid: "Email Adrässi ungültig" + parent_email_input_label: "Email Adrässi vo dine Eltere" + parent_email_input_placeholder: "Bitte gib dMail Adrässi vo dine Eltere a" + parent_email_send: "Email sände" + parent_email_sent: "Email gsändet!" + parent_email_title: "Wie isch dEmail Adrässi vo dine Eltere?" + parents: "Für Eltere" + parents_title: "Liebi Eltere, Ihres Chind isch am Lerne wieme programmiert. Wen Sie im helfe?" + parents_blurb1: "Ihres CHind hed __nLevels__ levels gschpilt und hed programmier Basics glernd. Helfed Sie soch dInträssi für sProgrammiere ufrecht zhalte und unterschtützed Sie in idem Sie es Abo chaufed." + parents_blurb1a: "Programmiere isch en wichtigi Begabig wo Ihres Chind als Erwachsene sicher wird bruche. Ab 2020 werded 77% vo allne Jobs eifachi Programmierkentniss benötige und die wos behersched werded uf de ganze Welt gsuecht. Hend Sie gwüsst das Programmiere de best bezallti Uni abschluss isch?" + parents_blurb2: "Für $9.99 USD/im Monät, würd Ihres Chind jedes Wuche neue und spannendi Challenges becho und professionelle E-Mail Support!" + parents_blurb3: "Kei Risikos, 100% Geld zrugg Garantie und ganz eifaches deaboniere mid eim Klick" + payment_methods: "Zalligs Methode" + payment_methods_title: "Akzeptierti Zalligs Methode" + payment_methods_blurb1: "Mier akzeptiered immoment Kreditchartene und Alipay." # payment_methods_blurb2: "If you require an alternate form of payment, please contact" # stripe_description: "Monthly Subscription" -# subscription_required_to_play: "You'll need a subscription to play this level." + subscription_required_to_play: "Du bruchsch es Abo um das Level zspile." # unlock_help_videos: "Subscribe to unlock all video tutorials." # personal_sub: "Personal Subscription" # Accounts Subscription View below -# loading_info: "Loading subscription information..." -# managed_by: "Managed by" -# will_be_cancelled: "Will be cancelled on" -# currently_free: "You currently have a free subscription" + loading_info: "Lade Abo Informatione..." + managed_by: "Verwaltet vo" + will_be_cancelled: "Wird abbroche am" + currently_free: "Du hesch jetzt grad es frii Abo" # currently_free_until: "You currently have a free subscription until" # was_free_until: "You had a free subscription until" -# managed_subs: "Managed Subscriptions" + managed_subs: "Abos verwalte" # managed_subs_desc: "Add subscriptions for other players (students, children, etc.)" # group_discounts: "Group discounts" # group_discounts_1: "We also offer group discounts for bulk subscriptions." -# group_discounts_1st: "1st subscription" -# group_discounts_full: "Full price" -# group_discounts_2nd: "Subscriptions 2-11" -# group_discounts_20: "20% off" -# group_discounts_12th: "Subscriptions 12+" -# group_discounts_40: "40% off" -# subscribing: "Subscribing..." -# recipient_emails_placeholder: "Enter email address to subscribe, one per line." -# subscribe_users: "Subscribe Users" -# users_subscribed: "Users subscribed:" + group_discounts_1st: "Erstes Abonement" + group_discounts_full: "de ganz Priis" + group_discounts_2nd: "Aboniere 2-11" + group_discounts_20: "20% billiger" + group_discounts_12th: "Aboniere 12+" + group_discounts_40: "40% billiger" + subscribing: "Am Aboniere..." + recipient_emails_placeholder: "Gib dini Mails zum Aboniere i, eine pro Linie:" + subscribe_users: "Abonier Users" + users_subscribed: "Users aboniert:" # no_users_subscribed: "No users subscribed, please double check your email addresses." # current_recipients: "Current Recipients" -# unsubscribing: "Unsubscribing..." -# subscribe_prepaid: "Click Subscribe to use prepaid code" -# using_prepaid: "Using prepaid code for monthly subscription" + unsubscribing: "Am Abo chünde" + subscribe_prepaid: "Klick Aboniere um en PrePaid Code izlöse" + using_prepaid: "Bruch en PrePaid Code um en Monet zAboniere" choose_hero: -# choose_hero: "Choose Your Hero" -# programming_language: "Programming Language" -# programming_language_description: "Which programming language do you want to use?" -# default: "Default" + choose_hero: "Wähl din Held" + programming_language: "Programmiersprach" + programming_language_description: "Weli Programmiersprach wetsch benutze?" + default: "Standard" # experimental: "Experimental" python_blurb: "Eifach und doch mächtig." javascript_blurb: "D Internetsproch." @@ -476,22 +476,22 @@ module.exports = nativeDescription: "Deutsch (Schweiz)", englishDescription: "Ge lua_blurb: "D Sproch für Game Scripts." io_blurb: "Eifach aber undurchsichtig." # status: "Status" -# hero_type: "Type" -# weapons: "Weapons" -# weapons_warrior: "Swords - Short Range, No Magic" -# weapons_ranger: "Crossbows, Guns - Long Range, No Magic" -# weapons_wizard: "Wands, Staffs - Long Range, Magic" -# attack: "Damage" # Can also translate as "Attack" -# health: "Health" -# speed: "Speed" -# regeneration: "Regeneration" -# range: "Range" # As in "attack or visual range" + hero_type: "Typ" + weapons: "Waffene" + weapons_warrior: "Schwärter - churzi Richwiti, kei Magie" + weapons_ranger: "Armbrüscht, Knarre - grossi Richwiti, kei Magie" + weapons_wizard: "Zauberstäb - grossi Richwiti, Magie" + attack: "Schadä" # Can also translate as "Attack" + health: "Läbä" + speed: "Schnelligkeit" + regeneration: "Regeneration" + range: "Richwiti" # As in "attack or visual range" # blocks: "Blocks" # As in "this shield blocks this much damage" # backstab: "Backstab" # As in "this dagger does this much backstab damage" -# skills: "Skills" + skills: "Fähigkeite" # attack_1: "Deals" # attack_2: "of listed" -# attack_3: "weapon damage." + attack_3: "Waffeschade." # health_1: "Gains" # health_2: "of listed" # health_3: "armor health." @@ -501,15 +501,15 @@ module.exports = nativeDescription: "Deutsch (Schweiz)", englishDescription: "Ge # level_to_unlock: "Level to unlock:" # Label for which level you have to beat to unlock a particular hero (click a locked hero in the store to see) # restricted_to_certain_heroes: "Only certain heroes can play this level." -# skill_docs: + skill_docs: # writable: "writable" # Hover over "attack" in Your Skills while playing a level to see most of this # read_only: "read-only" -# action_name: "name" + action_name: "name" # action_cooldown: "Takes" -# action_specific_cooldown: "Cooldown" -# action_damage: "Damage" -# action_range: "Range" -# action_radius: "Radius" + action_specific_cooldown: "Abklingziit" + action_damage: "Schade" + action_range: "Richwiti" + action_radius: "Radius" # action_duration: "Duration" # example: "Example" # ex: "ex" # Abbreviation of "example" @@ -519,16 +519,16 @@ module.exports = nativeDescription: "Deutsch (Schweiz)", englishDescription: "Ge # returns: "Returns" # granted_by: "Granted by" -# save_load: -# granularity_saved_games: "Saved" -# granularity_change_history: "History" + save_load: + granularity_saved_games: "Gschpeicheret" + granularity_change_history: "Verlauf" options: # general_options: "General Options" # Check out the Options tab in the Game Menu while playing a level -# volume_label: "Volume" -# music_label: "Music" + volume_label: "Luutstärchi" + music_label: "Musig" # music_description: "Turn background music on/off." -# autorun_label: "Autorun" + autorun_label: "Autorun" # autorun_description: "Control automatic code execution." # editor_config: "Editor Config" editor_config_title: "Editor Konfiguration" @@ -568,21 +568,21 @@ module.exports = nativeDescription: "Deutsch (Schweiz)", englishDescription: "Ge # scott_blurb: "Reasonable One" # nick_title: "Cofounder" # nick_blurb: "Motivation Guru" -# michael_title: "Programmer" -# michael_blurb: "Sys Admin" -# matt_title: "Programmer" + michael_title: "Programmierer" + michael_blurb: "System Admin" + matt_title: "Programmierer" # matt_blurb: "Bicyclist" # cat_title: "Chief Artisan" -# cat_blurb: "Airbender" -# josh_title: "Game Designer" -# josh_blurb: "Floor Is Lava" -# jose_title: "Music" + cat_blurb: "Luftbändiger" + josh_title: "Game Designer" + josh_blurb: "De Bode isch Lava" + jose_title: "Musig" # jose_blurb: "Taking Off" # retrostyle_title: "Illustration" # retrostyle_blurb: "RetroStyle Games" -# teachers: -# title: "CodeCombat: Info for Teachers" + teachers: + title: "CodeCombat: Info für Lehrer" # intro_1: "CodeCombat is an online game that teaches programming. Students write code in real programming languages." # intro_2: "No experience required!" # free_title: "How much does it cost?" @@ -618,11 +618,11 @@ module.exports = nativeDescription: "Deutsch (Schweiz)", englishDescription: "Ge versions: save_version_title: "Neui Version speichere" new_major_version: "Neui Hauptversion" -# submitting_patch: "Submitting Patch..." + submitting_patch: "Patch am abgee" # cla_prefix: "To save changes, first you must agree to our" -# cla_url: "CLA" -# cla_suffix: "." -# cla_agree: "I AGREE" + cla_url: "CLA" + cla_suffix: "." + cla_agree: "Ich bi iverstandee" contact: contact_us: "CodeCombat kontaktiere" @@ -630,8 +630,8 @@ module.exports = nativeDescription: "Deutsch (Schweiz)", englishDescription: "Ge forum_prefix: "Für öffentlichi Sache versuechs mol stattdesse i " forum_page: "üsem Forum" forum_suffix: "." -# faq_prefix: "There's also a" -# faq: "FAQ" + faq_prefix: "Es gid au es" + faq: "FAQ" # subscribe_prefix: "If you need help figuring out a level, please" # subscribe: "buy a CodeCombat subscription" # subscribe_suffix: "and we'll be happy to help you with your code." @@ -648,11 +648,11 @@ module.exports = nativeDescription: "Deutsch (Schweiz)", englishDescription: "Ge autosave: "Änderige werded automatisch gspeicheret" me_tab: "Ich" picture_tab: "Bild" -# delete_account_tab: "Delete Your Account" -# wrong_email: "Wrong Email" + delete_account_tab: "Din Account lösche" + wrong_email: "Falschi Email Adrässe" upload_picture: "Es Bild ufelade" -# delete_this_account: "Delete this account permanently" -# god_mode: "God Mode" + delete_this_account: "Dä Account für immer Lösche" + god_mode: "Gott Modus" password_tab: "Passwort" emails_tab: "E-Mails" admin: "Admin" @@ -667,7 +667,7 @@ module.exports = nativeDescription: "Deutsch (Schweiz)", englishDescription: "Ge email_notifications_summary: "Istellige für personalisierti, automatischi E-Mail Notifikatione im Zemehang mit dine CodeCombat Aktivitäte" email_any_notes: "Alli Notifikatione" email_any_notes_description: "Deaktiviere zum kei Aktivitäts-Notifikatione meh per E-Mail becho." -# email_news: "News" + email_news: "Neuigkeite" # email_recruit_notes: "Job Opportunities" # email_recruit_notes_description: "If you play really well, we may contact you about getting you a (better) job." # contributor_emails: "Contributor Class Emails" @@ -683,16 +683,16 @@ module.exports = nativeDescription: "Deutsch (Schweiz)", englishDescription: "Ge # job_profile_approved: "Your job profile has been approved by CodeCombat. Employers will be able to see it until you either mark it inactive or it has not been changed for four weeks." # job_profile_explanation: "Hi! Fill this out, and we will get in touch about finding you a software developer job." # sample_profile: "See a sample profile" -# view_profile: "View Your Profile" + view_profile: "Dis Profil aluege" keyboard_shortcuts: keyboard_shortcuts: "Shortcuts uf de Tastatur" space: "Space" enter: "Enter" escape: "Escape" -# shift: "Shift" -# run_code: "Run current code." -# run_real_time: "Run in real time." + shift: "Shift" + run_code: "De jetzig Code laufe laa." + run_real_time: "In Echtziit laufe laa." continue_script: "Nochem aktuelle Script fortsetze." skip_scripts: "Alli überspringbare Scripts überspringe." toggle_playback: "Play/Pause istelle." @@ -703,7 +703,7 @@ module.exports = nativeDescription: "Deutsch (Schweiz)", englishDescription: "Ge toggle_grid: "Gitter ischalte/usschalte." toggle_pathfinding: "Wegfinder ischalte/usschalte." beautify: "Mach din Code schöner, indem du sini Formatierig standartisiersch." -# maximize_editor: "Maximize/minimize code editor." + maximize_editor: "Maximize/minimize de code editor." community: main_title: "CodeCombat Community" @@ -1289,7 +1289,7 @@ module.exports = nativeDescription: "Deutsch (Schweiz)", englishDescription: "Ge # player_code: "Player Code" employers: -# deprecation_warning_title: "Sorry, CodeCombat is not recruiting right now." + deprecation_warning_title: "Sorry, CodeCombat rekrutiert grad nid." # deprecation_warning: "We are focusing on beginner levels instead of finding expert developers for the time being." hire_developers_not_credentials: "Stell Entwickler ah, nid Zügnis." # We are not actively recruiting right now, so there's no need to add new translations for the rest of this section. # get_started: "Get Started" diff --git a/app/locale/en.coffee b/app/locale/en.coffee index 885cb6d0c..6a5902a75 100644 --- a/app/locale/en.coffee +++ b/app/locale/en.coffee @@ -588,7 +588,7 @@ intro_2: "No experience required!" free_title: "How much does it cost?" cost_china: "CodeCombat in China is free for the first five levels, after which it costs $9.99 per month for access to our other 120+ levels on our exclusive China servers." - free_1: "CodeCombat Basic is FREE! There are 70+ free levels which cover every concept." + free_1: "CodeCombat Basic is FREE! There are 80+ free levels which cover every concept." # {change} free_2: "A monthly subscription provides access to video tutorials and extra practice levels." teacher_subs_title: "Teachers get free subscriptions!" teacher_subs_1: "Please contact" diff --git a/app/locale/id.coffee b/app/locale/id.coffee index 1d7e1ad02..cc17b3d49 100644 --- a/app/locale/id.coffee +++ b/app/locale/id.coffee @@ -15,12 +15,12 @@ module.exports = nativeDescription: "Bahasa Indonesia", englishDescription: "Ind nav: play: "Levels" # The top nav bar entry where players choose which levels to play - community: "Community" + community: "Komunitas" editor: "Editor" blog: "Blog" forum: "Forum" account: "Akun" - profile: "Profile" + profile: "Profil" stats: "Mulai" code: "Code" admin: "Admin" # Only shows up when you are an admin @@ -33,7 +33,7 @@ module.exports = nativeDescription: "Bahasa Indonesia", englishDescription: "Ind # teachers: "Teachers" modal: - close: "Close" + close: "Tutup" okay: "Okay" not_found: @@ -42,8 +42,8 @@ module.exports = nativeDescription: "Bahasa Indonesia", englishDescription: "Ind diplomat_suggestion: # title: "Help translate CodeCombat!" # This shows up when a player switches to a non-English language using the language selector. # sub_heading: "We need your language skills." - pitch_body: "We develop CodeCombat in English, but we already have players all over the world. Many of them want to play in Indonesian but don't speak English, so if you can speak both, please consider signing up to be a Diplomat and help translate both the CodeCombat website and all the levels into Indonesian." - missing_translations: "Until we can translate everything into Indonesian, you'll see English when Indonesian isn't available." + pitch_body: "Kami mengembangkan CodeCombat dalam bahasa Inggris, tapi kami sudah memiliki pemain di seluruh dunia. Banyak dari mereka ingin bermain di Indonesia, tetapi tidak berbicara bahasa Inggris, jadi jika Anda dapat berbicara, silakan mempertimbangkan untuk mendaftar untuk menjadi Diplomat dan membantu menerjemahkan kedua situs CodeCombat dan semua tingkatan ke Indonesia." + missing_translations: "Hingga kami bisa menerjemahkan semuanya ke dalam bahasa Indonesia, Anda akan melihat bahasa Inggris ketika Indonesia belum tersedia." # learn_more: "Learn more about being a Diplomat" # subscribe_as_diplomat: "Subscribe as a Diplomat" @@ -58,12 +58,12 @@ module.exports = nativeDescription: "Bahasa Indonesia", englishDescription: "Ind # owned: "Owned" # For items you own locked: "Terkunci" # purchasable: "Purchasable" # For a hero you unlocked but haven't purchased - available: "Trsedia" + available: "Tersedia" # skills_granted: "Skills Granted" # Property documentation details heroes: "Heroes" # Tooltip on hero shop button from /play # achievements: "Achievements" # Tooltip on achievement list button from /play account: "Akun" # Tooltip on account button from /play - settings: "Settings" # Tooltip on settings button from /play + settings: "Pengaturan" # Tooltip on settings button from /play # poll: "Poll" # Tooltip on poll button from /play # next: "Next" # Go from choose hero to choose inventory before playing a level # change_hero: "Change Hero" # Go back from choose inventory to choose hero diff --git a/app/locale/ja.coffee b/app/locale/ja.coffee index 993991ed6..397e1be24 100644 --- a/app/locale/ja.coffee +++ b/app/locale/ja.coffee @@ -358,7 +358,7 @@ module.exports = nativeDescription: "日本語", englishDescription: "Japanese", leaderboard: leaderboard: "リーダーボード" - view_other_solutions: "他のソリューションを見る" # {change} + view_other_solutions: "リーダーボードを見る" scores: "スコア" top_players: "上位プレイヤー順" day: "今日" @@ -836,8 +836,8 @@ module.exports = nativeDescription: "日本語", englishDescription: "Japanese", contribute: page_title: "コントリビュート" intro_blurb: "CodeCombat は100%オープンソースです!何百もの熱心なプレイヤーが私たちがゲームを作るのを手伝っています。私たちと一緒に CodeCombat の次のチャプターを作って世界中のプレイヤーにプログラミングを教えましょう!" -# alert_account_message_intro: "Hey there!" -# alert_account_message: "To subscribe for class emails, you'll need to be logged in first." + alert_account_message_intro: "やあ、こんにちは!" + alert_account_message: "クラスのメールを購読するには,まずログインが必要です。" archmage_introduction: "ゲームを作る上で一番重要なのは、たくさんの要素を合成することです。グラフィック、サウンド、リアルタイムネットワーキング、ソーシャルネットワーキング、一般的なプログラミング、ローレベルのデータベースマネジメント、管理画面のデザインやインターフェイスなど多岐に渡ります。やらなくてはいけないことはたくさんあります。もしあなたが経験豊富なプログラマであればアーキメイジになって CodeCombat のコアにコミットしましょう。ぜひとも私たちの最高のプログラミングゲームを手伝ってください。" class_attributes: "クラスの属性" archmage_attribute_1_pref: "" @@ -851,17 +851,17 @@ module.exports = nativeDescription: "日本語", englishDescription: "Japanese", join_url_email: "メール" join_url_hipchat: "公開の HipChat のルーム" archmage_subscribe_desc: "コーディングの機会やアナウンスをメールで受け取る" -# artisan_introduction_pref: "We must construct additional levels! People be clamoring for more content, and we can only build so many ourselves. Right now your workstation is level one; our level editor is barely usable even by its creators, so be wary. If you have visions of campaigns spanning for-loops to" -# artisan_introduction_suf: ", then this class might be for you." -# artisan_attribute_1: "Any experience in building content like this would be nice, such as using Blizzard's level editors. But not required!" -# artisan_attribute_2: "A hankering to do a whole lot of testing and iteration. To make good levels, you need to take it to others and watch them play it, and be prepared to find a lot of things to fix." -# artisan_attribute_3: "For the time being, endurance en par with an Adventurer. Our Level Editor is super preliminary and frustrating to use. You have been warned!" -# artisan_join_desc: "Use the Level Editor in these steps, give or take:" -# artisan_join_step1: "Read the documentation." -# artisan_join_step2: "Create a new level and explore existing levels." -# artisan_join_step3: "Find us in our public HipChat room for help." -# artisan_join_step4: "Post your levels on the forum for feedback." -# artisan_subscribe_desc: "Get emails on level editor updates and announcements." + artisan_introduction_pref: "私たちは、追加のレベルを建設しなければなりません!皆さんはもっとコンテンツを、と叫んでいますが、私達がつくれるのは自分たちの分だけです。今、あなたのワークステーションはレベル1です。私達のレベルエディタをつかえばそんなクリエイターでもギリギリ使えます、そう警戒しないで。あなたがfor-loopにまたがるキャンペーンのビジョンを" + artisan_introduction_suf: "にもっているなら、このクラスはあなたのためになるかもしれません。" + artisan_attribute_1: "Blizzardのレベルエディタなどの構築経験は歓迎しますが、必須ではありません!" + artisan_attribute_2: "全体のテストを何度もすることを願ってます。 よいレベルを作るには 他の人のを真似て見てプレイしてみることが必要です。そしてそこから修正のための多くのものを見つけて準備しましょう。" + artisan_attribute_3: "時間がかかることで, 冒険者と並ぶくらい我慢しなければなりません。 私達のレベルエディターは予備動作が長く使っているとイライラするかもしれません。気をつけてくださいね!" + artisan_join_desc: "レベルエディタを使うために以下のステップを利用してください。" + artisan_join_step1: "ドキュメントを読む" + artisan_join_step2: "新しいレベルを作成し、すでにあるレベルか探す" + artisan_join_step3: "ヘルプが必要なとき公開HipChatルームで私達を探す" + artisan_join_step4: "フィードバックのためフォーラムにあなたのレベルを投稿する" + artisan_subscribe_desc: "レベルエディタアップデートやアナウンスをメールで受け取る" # adventurer_introduction: "Let's be clear about your role: you are the tank. You're going to take heavy damage. We need people to try out brand-new levels and help identify how to make things better. The pain will be enormous; making good games is a long process and no one gets it right the first time. If you can endure and have a high constitution score, then this class might be for you." # adventurer_attribute_1: "A thirst for learning. You want to learn how to code and we want to teach you how to code. You'll probably be doing most of the teaching in this case, though." # adventurer_attribute_2: "Charismatic. Be gentle but articulate about what needs improving, and offer suggestions on how to improve." @@ -912,17 +912,17 @@ module.exports = nativeDescription: "日本語", englishDescription: "Japanese", # games_simulated_for: "Games simulated for you:" # games_simulated: "Games simulated" # games_played: "Games played" -# ratio: "Ratio" -# leaderboard: "Leaderboard" + ratio: "比率 " + leaderboard: "リーダーボード" # battle_as: "Battle as " summary_your: "あなたの " summary_matches: "戦闘数 - " summary_wins: " 勝利数, " summary_losses: " 敗北数" -# rank_no_code: "No New Code to Rank" + rank_no_code: "新しいコードがランクにありません" # rank_my_game: "Rank My Game!" -# rank_submitting: "Submitting..." -# rank_submitted: "Submitted for Ranking" + rank_submitting: "送信中..." + rank_submitted: "ランキングに送信されました。" # rank_failed: "Failed to Rank" # rank_being_ranked: "Game Being Ranked" # rank_last_submitted: "submitted " diff --git a/app/styles/admin/analytics-subscriptions.sass b/app/styles/admin/analytics-subscriptions.sass index a1318c659..ae00c681f 100644 --- a/app/styles/admin/analytics-subscriptions.sass +++ b/app/styles/admin/analytics-subscriptions.sass @@ -47,7 +47,14 @@ background-color: blanchedalmond font-size: 10pt + .subscribers-thead + font-size: 10pt + th + padding: 2px + .subscribers-tbody font-size: 9pt td padding: 2px + max-width: 220px + overflow: hidden diff --git a/app/styles/clans/clan-details.sass b/app/styles/clans/clan-details.sass index 20c537f7c..30afaa372 100644 --- a/app/styles/clans/clan-details.sass +++ b/app/styles/clans/clan-details.sass @@ -51,7 +51,7 @@ .level-progression-cell background-color: lightblue border: 1px solid gray - // cursor: pointer + cursor: pointer padding: 4px .level-popup-container diff --git a/app/templates/admin/analytics-subscriptions.jade b/app/templates/admin/analytics-subscriptions.jade index 4383ae2c5..55e1a359d 100644 --- a/app/templates/admin/analytics-subscriptions.jade +++ b/app/templates/admin/analytics-subscriptions.jade @@ -36,14 +36,12 @@ block content each value in point.values div #{value} - div *Stripe APIs do not return information about inactive subs. - h2 Recent Subscribers if !subscribers || subscribers.length < 1 h4 Fetching recent subscribers... else table.table.table-striped.table-condensed - thead + thead.subscribers-thead tr th Sub ID th User Start @@ -52,19 +50,22 @@ block content th Cancelled else th - th - //- th Name + if subscriberSponsored + th Sponsored + else + th th Email th Hero th Level th Last Level th Age th Spoken + th Clans tbody.subscribers-tbody each subscriber in subscribers tr td - a(href="https://dashboard.stripe.com/customers/#{subscriber.customerID}", target="_blank")= subscriber.subscriptionID + a(href="https://dashboard.stripe.com/customers/#{subscriber.customerID}", target="_blank")= subscriber.subID td= subscriber.user.dateCreated.substring(0, 10) td= subscriber.start.substring(0, 10) td @@ -72,15 +73,17 @@ block content span= subscriber.cancel.substring(0, 10) td if subscriber.user.stripe.sponsorID - span Sponsored - //- td - //- a(href="/user/#{subscriber.user._id}")= subscriber.user.name || 'Anoner' + span Yes td= subscriber.user.emailLower td= subscriber.hero td= subscriber.level td= subscriber.user.lastLevel td= subscriber.user.ageRange td= subscriber.user.preferredLanguage + if subscriber.user.clans + td= subscriber.user.clans.length + else + td h2 Subscriptions if !subs || subs.length < 1 @@ -93,8 +96,9 @@ block content th Total th Started th Cancelled - th Net + th Net (cancelled) th Ended + th Net (ended) tbody each sub in subs tr @@ -104,3 +108,4 @@ block content td= sub.cancelled td= sub.started - sub.cancelled td= sub.ended + td= sub.started - sub.ended diff --git a/app/templates/clans/clan-details.jade b/app/templates/clans/clan-details.jade index 97afcae28..f2129f02a 100644 --- a/app/templates/clans/clan-details.jade +++ b/app/templates/clans/clan-details.jade @@ -103,11 +103,14 @@ block content a(href="/user/#{member.id}")= member.get('name') || 'Anoner' if memberLevelProgression && memberLevelProgression[member.id] each levelInfo in memberLevelProgression[member.id] - td.level-progression-cell + td.level-progression-cell(data-level-info=levelInfo) .level-popup-container - div Level: #{levelInfo.level} - div Playtime: #{levelInfo.playtime} - div Last played: #{levelInfo.changed} + h3 #{levelInfo.level} + p + div Playtime: #{levelInfo.playtime}s + div Last played: #{levelInfo.changed} + if isOwner || me.isAdmin() + strong Click to view solution. td.level-progression-cell-name(colspan="#{memberMaxLevelCount - memberLevelProgression[member.id].length + 1}")= memberLevelProgression[member.id][memberLevelProgression[member.id].length - 1].level else td(colspan="#{memberMaxLevelCount + 1}") diff --git a/app/templates/community-view.jade b/app/templates/community-view.jade index 21511f6bc..b13039bc2 100644 --- a/app/templates/community-view.jade +++ b/app/templates/community-view.jade @@ -12,7 +12,7 @@ block content a(href="/editor/level") img(src="/images/pages/community/level.png") h2 - a.spl(href="/editor/level", data-i18n="editor.level_title") + a(href="/editor/level", data-i18n="editor.level_title") p span.spr(data-i18n="community.level_editor_prefix") Use the CodeCombat a(href="/editor/level", data-i18n="editor.level_title") @@ -22,7 +22,7 @@ block content a(href="/editor/thang") img(src="/images/pages/community/thang.png") h2 - a.spl(href="/editor/thang", data-i18n="editor.thang_title") + a(href="/editor/thang", data-i18n="editor.thang_title") p span.spr(data-i18n="community.thang_editor_prefix") We call units within the game 'thangs'. Use the a(href="/editor/thang", data-i18n="editor.thang_title") @@ -32,7 +32,7 @@ block content a(href="/editor/article") img(src="/images/pages/community/article.png") h2 - a.spl(href="/editor/article", data-i18n="editor.article_title") + a(href="/editor/article", data-i18n="editor.article_title") p span.spr(data-i18n="community.article_editor_prefix") See a mistake in some of our docs? Want to make some instructions for your own creations? Check out the a(href="/editor/article", data-i18n="editor.article_title") diff --git a/app/templates/editor/component/add-thang-components-modal.jade b/app/templates/editor/component/add-thang-components-modal.jade index 2d40a7aee..0cc20beea 100644 --- a/app/templates/editor/component/add-thang-components-modal.jade +++ b/app/templates/editor/component/add-thang-components-modal.jade @@ -9,9 +9,9 @@ block modal-body-content for system in systems li.list-group-item div.item-title(data-toggle="collapse", data-target="##{system}").collapsed - span.glyphicon.glyphicon-chevron-down.text-muted - span.glyphicon.glyphicon-chevron-up.text-muted - a.spl= system + span.glyphicon.glyphicon-chevron-down.text-muted.spr + span.glyphicon.glyphicon-chevron-up.text-muted.spr + a= system span.spl.text-muted= nameLists[system] .collapse-panel.collapse(id=system) for component in components[system] diff --git a/app/templates/i18n/i18n-home-view.jade b/app/templates/i18n/i18n-home-view.jade index f89c2eff2..5e14b40e3 100644 --- a/app/templates/i18n/i18n-home-view.jade +++ b/app/templates/i18n/i18n-home-view.jade @@ -14,7 +14,8 @@ block content th Translated Name th Type th Specifically Covered - th Generally Covered + if showGeneralCoverage + th Generally Covered if selectedLanguage for model in collection.models @@ -29,4 +30,5 @@ block content td= translatedName td= model.constructor.className td(class=model.specificallyCovered ? 'success' : 'danger')= model.specificallyCovered ? 'Yes' : 'No' - td(class=model.generallyCovered ? 'success' : 'danger')= model.generallyCovered ? 'Yes' : 'No' + if showGeneralCoverage + td(class=model.generallyCovered ? 'success' : 'danger')= model.generallyCovered ? 'Yes' : 'No' diff --git a/app/views/admin/AnalyticsSubscriptionsView.coffee b/app/views/admin/AnalyticsSubscriptionsView.coffee index cceebef4f..4daf9ad4a 100644 --- a/app/views/admin/AnalyticsSubscriptionsView.coffee +++ b/app/views/admin/AnalyticsSubscriptionsView.coffee @@ -10,7 +10,7 @@ require 'vendor/d3' module.exports = class AnalyticsSubscriptionsView extends RootView id: 'admin-analytics-subscriptions-view' template: template - targetSubCount: 2000 + targetSubCount: 1200 constructor: (options) -> super options @@ -25,6 +25,7 @@ module.exports = class AnalyticsSubscriptionsView extends RootView context.subs = _.cloneDeep(@subs ? []).reverse() context.subscribers = @subscribers ? [] context.subscriberCancelled = _.find context.subscribers, (subscriber) -> subscriber.cancel + context.subscriberSponsored = _.find context.subscribers, (subscriber) -> subscriber.user?.stripe?.sponsorID context.total = @total ? 0 context.cancelled = @cancelled ? 0 context.monthlyChurn = @monthlyChurn ? 0.0 @@ -46,9 +47,9 @@ module.exports = class AnalyticsSubscriptionsView extends RootView refreshData: -> return unless me.isAdmin() @resetSubscriptionsData() - @getSubscribers() @getCancellations (cancellations) => - @getSubscriptions(cancellations) + @getSubscriptions cancellations, (subscriptions) => + @getSubscribers(subscriptions) getCancellations: (done) -> options = @@ -62,25 +63,34 @@ module.exports = class AnalyticsSubscriptionsView extends RootView done(cancellations) @supermodel.addRequestResource('get_cancellations', options, 0).load() - getSubscribers: -> + getSubscribers: (subscriptions) -> + maxSubscribers = 40 + + subscribers = _.filter subscriptions, (a) -> a.userID? + subscribers.sort (a, b) -> b.start.localeCompare(a.start) + subscribers = subscribers.slice(0, maxSubscribers) + subscriberUserIDs = _.map subscribers, (a) -> a.userID + options = url: '/db/subscription/-/subscribers' method: 'POST' - data: {maxCount: 30} + data: {ids: subscriberUserIDs} options.error = (model, response, options) => return if @destroyed console.error 'Failed to get subscribers', response - options.success = (subscribers, response, options) => + options.success = (userMap, response, options) => return if @destroyed - @subscribers = subscribers - for subscriber in @subscribers + for subscriber in subscribers + continue unless subscriber.userID of userMap + subscriber.user = userMap[subscriber.userID] subscriber.level = User.levelFromExp subscriber.user.points if hero = subscriber.user.heroConfig?.thangType subscriber.hero = _.invert(ThangType.heroes)[hero] + @subscribers = subscribers @render?() @supermodel.addRequestResource('get_subscribers', options, 0).load() - getSubscriptions: (cancellations=[]) -> + getSubscriptions: (cancellations=[], done) -> options = url: '/db/subscription/-/subscriptions' method: 'GET' @@ -102,6 +112,7 @@ module.exports = class AnalyticsSubscriptionsView extends RootView subDayMap[endDay]['end']++ for cancellation in cancellations if cancellation.subID is sub.subID + sub.cancel = cancellation.cancel cancelDay = cancellation.cancel.substring(0, 10) subDayMap[cancelDay] ?= {} subDayMap[cancelDay]['cancel'] ?= 0 @@ -132,6 +143,7 @@ module.exports = class AnalyticsSubscriptionsView extends RootView @monthlyGrowth = (endMonthTotal / startMonthTotal - 1) * 100 @updateAnalyticsGraphData() @render?() + done(subs) @supermodel.addRequestResource('get_subscriptions', options, 0).load() updateAnalyticsGraphData: -> @@ -170,7 +182,7 @@ module.exports = class AnalyticsSubscriptionsView extends RootView color: 'red' strokeWidth: 1 lineMetadata[netSubsID] = - description: '7-day Average Net Subscriptions' + description: '7-day Average Net Subscriptions (started - ended)' color: 'black' strokeWidth: 4 diff --git a/app/views/clans/ClanDetailsView.coffee b/app/views/clans/ClanDetailsView.coffee index 9f56cd3e5..66d2d7577 100644 --- a/app/views/clans/ClanDetailsView.coffee +++ b/app/views/clans/ClanDetailsView.coffee @@ -23,6 +23,7 @@ module.exports = class ClanDetailsView extends RootView 'click .edit-name-save-btn': 'onEditNameSave' 'click .join-clan-btn': 'onJoinClan' 'click .leave-clan-btn': 'onLeaveClan' + 'click .level-progression-cell': 'onClickLevel' 'click .remove-member-btn': 'onRemoveMember' 'mouseenter .level-progression-cell': 'onMouseEnterPoint' 'mouseleave .level-progression-cell': 'onMouseLeavePoint' @@ -131,8 +132,10 @@ module.exports = class ClanDetailsView extends RootView @memberLevelProgression[user] ?= [] levelInfo = level: levelSession.get('levelName') + levelID: levelSession.get('levelID') changed: new Date(levelSession.get('changed')).toLocaleString() playtime: levelSession.get('playtime') + sessionID: levelSession.id @memberLevelProgression[user].push levelInfo @memberMaxLevelCount = 0 @memberLanguageMap = {} @@ -161,6 +164,12 @@ module.exports = class ClanDetailsView extends RootView onMouseLeavePoint: (e) -> $(e.target).find('.level-popup-container').hide() + onClickLevel: (e) -> + levelInfo = $(e.target).data 'level-info' + return unless levelInfo?.levelID? and levelInfo?.sessionID? + url = "/play/level/#{levelInfo.levelID}?session=#{levelInfo.sessionID}&observing=true" + window.open url, '_blank' + onDeleteClan: (e) -> return @openModalView(new AuthModal()) if me.isAnonymous() return unless window.confirm("Delete Clan?") @@ -211,6 +220,7 @@ module.exports = class ClanDetailsView extends RootView @supermodel.addRequestResource( 'leave_clan', options).load() onRemoveMember: (e) -> + return unless window.confirm("Remove Hero?") if memberID = $(e.target).data('id') options = url: "/db/clan/#{@clanID}/remove/#{memberID}" diff --git a/app/views/i18n/I18NHomeView.coffee b/app/views/i18n/I18NHomeView.coffee index 70c52a2e4..f4e05d063 100644 --- a/app/views/i18n/I18NHomeView.coffee +++ b/app/views/i18n/I18NHomeView.coffee @@ -73,6 +73,7 @@ module.exports = class I18NHomeView extends RootView covered = (m for m in @aggregateModels.models when m.specificallyCovered).length total = @aggregateModels.models.length c.progress = if total then parseInt(100 * covered / total) else 100 + c.showGeneralCoverage = /-/.test(@selectedLanguage ? 'en') # Only relevant for languages with more than one family, like zh-HANS c diff --git a/server/clans/clan_handler.coffee b/server/clans/clan_handler.coffee index e77f817df..37a43102d 100644 --- a/server/clans/clan_handler.coffee +++ b/server/clans/clan_handler.coffee @@ -126,7 +126,7 @@ ClanHandler = class ClanHandler extends Handler return @sendNotFoundError(res) unless clan memberIDs = _.map clan.get('members') ? [], (memberID) -> memberID.toHexString?() or memberID memberIDs = memberIDs.slice 0, memberLimit - LevelSession.find {creator: {$in: memberIDs}}, 'changed codeLanguage creator creatorName levelName playtime state submittedCodeLanguage', (err, documents) => + LevelSession.find {creator: {$in: memberIDs}}, 'changed codeLanguage creator creatorName levelID levelName playtime state submittedCodeLanguage', (err, documents) => return @sendDatabaseError(res, err) if err? cleandocs = (LevelSessionHandler.formatEntity(req, doc) for doc in documents) @sendSuccess(res, cleandocs) diff --git a/server/payments/subscription_handler.coffee b/server/payments/subscription_handler.coffee index 2504d65ac..8a990cb01 100644 --- a/server/payments/subscription_handler.coffee +++ b/server/payments/subscription_handler.coffee @@ -67,7 +67,7 @@ class SubscriptionHandler extends Handler (done) => stripe.customers.retrieveSubscription customerID, subscriptionID, (err, subscription) => return done() if err - return unless subscription?.cancel_at_period_end + return done() unless subscription?.cancel_at_period_end cancellations.push cancel: new Date(subscription.canceled_at * 1000) subID: subscription.id @@ -82,74 +82,18 @@ class SubscriptionHandler extends Handler getSubscribers: (req, res) -> # console.log 'subscription_handler getSubscribers' return @sendForbiddenError(res) unless req.user?.isAdmin() - - maxReturnCount = req.body.maxCount or 20 - - # @subscribers ?= [] - # return @sendSuccess(res, @subscribers) unless _.isEmpty(@subscribers) - @subscribers = [] - - subscriberIDs = [] - - customersProcessed = 0 - nextBatch = (starting_after, done) => - options = limit: 100 - options.starting_after = starting_after if starting_after - stripe.customers.list options, (err, customers) => - return done(err) if err - customersProcessed += customers.data.length - - for customer in customers.data - break unless @subscribers.length < maxReturnCount - continue unless customer?.subscriptions?.data?.length > 0 - for subscription in customer.subscriptions.data - continue unless subscription.plan.id is 'basic' - - amount = subscription.plan.amount - if subscription?.discount?.coupon? - if subscription.discount.coupon.percent_off - amount = amount * (100 - subscription.discount.coupon.percent_off) / 100; - else if subscription.discount.coupon.amount_off - amount -= subscription.discount.coupon.amount_off - else if customer.discount?.coupon? - if customer.discount.coupon.percent_off - amount = amount * (100 - customer.discount.coupon.percent_off) / 100 - else if customer.discount.coupon.amount_off - amount -= customer.discount.coupon.amount_off - - continue unless amount > 0 - - subscriber = - customerID: customer.id - start: new Date(subscription.start * 1000) - subscriptionID: subscription.id - if subscription.metadata?.id? - subscriber.userID = subscription.metadata.id - subscriberIDs.push subscription.metadata.id - if subscription.cancel_at_period_end - subscriber.cancel = new Date(subscription.canceled_at * 1000) - subscriber.end = new Date(subscription.current_period_end * 1000) - @subscribers.push(subscriber) - - if customers.has_more and @subscribers.length < maxReturnCount - return nextBatch(customers.data[customers.data.length - 1].id, done) - else - return done() - nextBatch null, (err) => + subscriberUserIDs = req.body.ids or [] + User.find {_id: {$in: subscriberUserIDs}}, (err, users) => return @sendDatabaseError(res, err) if err - User.find {_id: {$in: subscriberIDs}}, (err, users) => - return @sendDatabaseError(res, err) if err - for user in users - subscriber.user = user for subscriber in @subscribers when subscriber.userID is user.id - @sendSuccess(res, @subscribers) + userMap = {} + userMap[user.id] = user for user in users + @sendSuccess(res, userMap) getSubscriptions: (req, res) -> # console.log 'subscription_handler getSubscriptions' # Returns a list of active subscriptions - # TODO: does not track sponsored subs, only basic # TODO: does not return free subs # TODO: add tests - # TODO: aggregate this data daily instead of providing it on demand # TODO: take date range as input # TODO: are ended counts correct for today? E.g. retries may complicate things. @@ -169,11 +113,13 @@ class SubscriptionHandler extends Handler continue unless invoice.subscription continue unless invoice.total > 0 continue unless invoice.lines?.data?[0]?.plan?.id is 'basic' - newInvoices.push + newInvoice = customerID: invoice.customer invoiceID: invoice.id subscriptionID: invoice.subscription date: new Date(invoice.date * 1000) + newInvoice.userID = invoice.lines.data[0].metadata.id if invoice.lines?.data?[0]?.metadata?.id + newInvoices.push newInvoice if invoices.has_more # console.log 'Fetching more invoices', @invoices.length, newInvoices.length return processInvoices(invoices.data[invoices.data.length - 1].id, done) @@ -193,20 +139,49 @@ class SubscriptionHandler extends Handler first: invoice.date last: invoice.date customerID: invoice.customerID - subs = [] - for subID of subMap - sub = - start: subMap[subID].first - subID: subID - customerID: subMap[subID].customerID - sub.cancel = subMap[subID].cancel if subMap[subID].cancel - oneMonthAgo = new Date() - oneMonthAgo.setUTCMonth(oneMonthAgo.getUTCMonth() - 1) - if subMap[subID].last < oneMonthAgo - sub.end = new Date(subMap[subID].last) - sub.end.setUTCMonth(sub.end.getUTCMonth() + 1) - subs.push sub - @sendSuccess(res, subs) + subMap[subID].userID = invoice.userID if invoice.userID + + # Check sponsored subscriptions + User.find {"stripe.sponsorSubscriptionID": {$exists: true}}, (err, sponsors) => + return @sendDatabaseError(res, err) if err + + createCheckSubFn = (customerID, subscriptionID) => + (done) => + stripe.customers.retrieveSubscription customerID, subscriptionID, (err, subscription) => + return done() if err + return done() unless subscription? + subMap[subscription.id] = + first: new Date(subscription.start * 1000) + subMap[subscription.id].userID = subscription.metadata.id if subscription.metadata?.id? + if subscription.cancel_at_period_end + subMap[subscription.id].cancel = new Date(subscription.canceled_at * 1000) + subMap[subscription.id].end = new Date(subscription.current_period_end * 1000) + done() + + tasks = [] + for user in sponsors + for recipient in user.get("stripe")?.recipients + tasks.push createCheckSubFn(user.get('stripe')?.customerID, recipient.subscriptionID) + async.parallel tasks, (err, results) => + return @sendDatabaseError(res, err) if err + + subs = [] + for subID of subMap + sub = + start: subMap[subID].first + subID: subID + customerID: subMap[subID].customerID + sub.cancel = subMap[subID].cancel if subMap[subID].cancel + oneMonthAgo = new Date() + oneMonthAgo.setUTCMonth(oneMonthAgo.getUTCMonth() - 1) + if subMap[subID].end? + sub.end = subMap[subID].end + else if subMap[subID].last < oneMonthAgo + sub.end = new Date(subMap[subID].last) + sub.end.setUTCMonth(sub.end.getUTCMonth() + 1) + sub.userID = subMap[subID].userID if subMap[subID].userID + subs.push sub + @sendSuccess(res, subs) subscribeUser: (req, user, done) -> if (not req.user) or req.user.isAnonymous() or user.isAnonymous()