diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index ba13bf1f29c..536a268e55d 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -1 +1 @@
-<!-- NOTE: All pull requests should have tests (rspec in Ruby, qunit in Javascript). If your code does not include test coverage, please include an explanation of why it was omitted. -->
+<!-- NOTE: All pull requests should have tests (rspec in Ruby, qunit in JavaScript). If your code does not include test coverage, please include an explanation of why it was omitted. -->
diff --git a/app/assets/javascripts/discourse/app/components/composer-editor.js b/app/assets/javascripts/discourse/app/components/composer-editor.js
index c1be68eda59..124cf210f97 100644
--- a/app/assets/javascripts/discourse/app/components/composer-editor.js
+++ b/app/assets/javascripts/discourse/app/components/composer-editor.js
@@ -288,7 +288,7 @@ export default Component.extend({
 
     // when adding two separate files with the same filename search for matching
     // placeholder already existing in the editor ie [Uploading: test.png...]
-    // and add order nr to the next one: [Uplodading: test.png(1)...]
+    // and add order nr to the next one: [Uploading: test.png(1)...]
     const escapedFilename = filename.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
     const regexString = `\\[${I18n.t("uploading_filename", {
       filename: escapedFilename + "(?:\\()?([0-9])?(?:\\))?",
diff --git a/app/assets/javascripts/discourse/app/controllers/create-account.js b/app/assets/javascripts/discourse/app/controllers/create-account.js
index 6dc0fa372eb..57b41f44493 100644
--- a/app/assets/javascripts/discourse/app/controllers/create-account.js
+++ b/app/assets/javascripts/discourse/app/controllers/create-account.js
@@ -268,7 +268,7 @@ export default Controller.extend(
         (isEmpty(this.accountUsername) || this.get("authOptions.email"))
       ) {
         // If email is valid and username has not been entered yet,
-        // or email and username were filled automatically by 3rd parth auth,
+        // or email and username were filled automatically by 3rd party auth,
         // then look for a registered username that matches the email.
         discourseDebounce(this, this.fetchExistingUsername, 500);
       }
diff --git a/app/assets/javascripts/discourse/app/controllers/second-factor-add-security-key.js b/app/assets/javascripts/discourse/app/controllers/second-factor-add-security-key.js
index d6b48db673c..48839d0bbb9 100644
--- a/app/assets/javascripts/discourse/app/controllers/second-factor-add-security-key.js
+++ b/app/assets/javascripts/discourse/app/controllers/second-factor-add-security-key.js
@@ -87,7 +87,7 @@ export default Controller.extend(ModalFunctionality, {
         attestation: "none",
         authenticatorSelection: {
           // see https://chromium.googlesource.com/chromium/src/+/master/content/browser/webauth/uv_preferred.md for why
-          // default value of preferred is not necesarrily what we want, it limits webauthn to only devices that support
+          // default value of preferred is not necessarily what we want, it limits webauthn to only devices that support
           // user verification, which usually requires entering a PIN
           userVerification: "discouraged",
         },
diff --git a/app/assets/javascripts/discourse/app/controllers/topic.js b/app/assets/javascripts/discourse/app/controllers/topic.js
index fcadfa4fefb..6699af2c537 100644
--- a/app/assets/javascripts/discourse/app/controllers/topic.js
+++ b/app/assets/javascripts/discourse/app/controllers/topic.js
@@ -1606,7 +1606,7 @@ export default Controller.extend(bufferedProperty("model"), {
         }
 
         // scroll to bottom is very specific to new posts from discobot
-        // hence the -2 check (dicobot id). We can shift all this code
+        // hence the -2 check (discobot id). We can shift all this code
         // to discobot plugin longer term
         if (
           topic.get("isPrivateMessage") &&
diff --git a/app/assets/javascripts/discourse/app/helpers/user-avatar.js b/app/assets/javascripts/discourse/app/helpers/user-avatar.js
index 20af1a2c020..e0893b1089c 100644
--- a/app/assets/javascripts/discourse/app/helpers/user-avatar.js
+++ b/app/assets/javascripts/discourse/app/helpers/user-avatar.js
@@ -59,7 +59,7 @@ function renderAvatar(user, options) {
         const description = get(user, "description");
         // if a description has been provided
         if (description && description.length > 0) {
-          // preprend the username before the description
+          // prepend the username before the description
           title = I18n.t("user.avatar.name_and_description", {
             name: displayName,
             description,
diff --git a/app/assets/javascripts/discourse/app/initializers/badging.js b/app/assets/javascripts/discourse/app/initializers/badging.js
index f5a73b64366..73c90b0aa19 100644
--- a/app/assets/javascripts/discourse/app/initializers/badging.js
+++ b/app/assets/javascripts/discourse/app/initializers/badging.js
@@ -1,4 +1,4 @@
-// Updates the PWA badging if avaliable
+// Updates the PWA badging if available
 export default {
   name: "badging",
   after: "message-bus",
diff --git a/app/assets/javascripts/discourse/app/lib/ajax.js b/app/assets/javascripts/discourse/app/lib/ajax.js
index 36330cabf39..b7be9db2ec9 100644
--- a/app/assets/javascripts/discourse/app/lib/ajax.js
+++ b/app/assets/javascripts/discourse/app/lib/ajax.js
@@ -128,7 +128,7 @@ export function ajax() {
         Session.current().set("csrfToken", null);
       }
 
-      // If it's a parsererror, don't reject
+      // If it's a parser error, don't reject
       if (xhr.status === 200) {
         return args.success(xhr);
       }
diff --git a/app/assets/javascripts/discourse/app/lib/autocomplete.js b/app/assets/javascripts/discourse/app/lib/autocomplete.js
index d95cc46e527..99b77405a97 100644
--- a/app/assets/javascripts/discourse/app/lib/autocomplete.js
+++ b/app/assets/javascripts/discourse/app/lib/autocomplete.js
@@ -99,7 +99,7 @@ export default function (options) {
   let div = null;
   let prevTerm = null;
 
-  // By default, when the autcomplete popup is rendered it has the
+  // By default, when the autocomplete popup is rendered it has the
   // first suggestion 'selected', and pressing enter key inserts
   // the first suggestion into the input box.
   // If you want to stop that behavior, i.e. have the popup renders
diff --git a/app/assets/javascripts/discourse/app/lib/eyeline.js b/app/assets/javascripts/discourse/app/lib/eyeline.js
index f7f318865d8..f2ca4a8c375 100644
--- a/app/assets/javascripts/discourse/app/lib/eyeline.js
+++ b/app/assets/javascripts/discourse/app/lib/eyeline.js
@@ -67,7 +67,7 @@ Eyeline.prototype.update = function () {
     }
 
     // It's seen if...
-    // ...the element is vertically within the top and botom
+    // ...the element is vertically within the top and bottom
     if (elemTop <= docViewBottom && elemTop >= docViewTop) {
       markSeen = true;
     }
diff --git a/app/assets/javascripts/discourse/app/lib/hash.js b/app/assets/javascripts/discourse/app/lib/hash.js
index 71396274b9e..a4fd849a880 100644
--- a/app/assets/javascripts/discourse/app/lib/hash.js
+++ b/app/assets/javascripts/discourse/app/lib/hash.js
@@ -1,6 +1,6 @@
 /*eslint no-bitwise:0 */
 
-// Note: before changing this be aware the same algo is used server side for avatars.
+// Note: before changing this be aware the same algorithm is used server side for avatars.
 export function hashString(str) {
   let hash = 0;
   for (let i = 0; i < str.length; i++) {
diff --git a/app/assets/javascripts/discourse/app/lib/page-tracker.js b/app/assets/javascripts/discourse/app/lib/page-tracker.js
index be741139785..76a937f195a 100644
--- a/app/assets/javascripts/discourse/app/lib/page-tracker.js
+++ b/app/assets/javascripts/discourse/app/lib/page-tracker.js
@@ -23,7 +23,7 @@ export function startPageTracking(router, appEvents, documentTitle) {
     return;
   }
   router.on("routeDidChange", (transition) => {
-    // we ocassionally prevent tracking of replaced pages when only query params changed
+    // we occasionally prevent tracking of replaced pages when only query params changed
     // eg: google analytics
     const replacedOnlyQueryParams =
       transition.urlMethod === "replace" && transition.queryParamsOnly;
diff --git a/app/assets/javascripts/discourse/app/lib/url.js b/app/assets/javascripts/discourse/app/lib/url.js
index ec875d40331..e107bfef6f0 100644
--- a/app/assets/javascripts/discourse/app/lib/url.js
+++ b/app/assets/javascripts/discourse/app/lib/url.js
@@ -33,7 +33,7 @@ const SERVER_SIDE_ONLY = [
   /^\/styleguide/,
 ];
 
-// The amount of height (in pixles) that we factor in when jumpEnd is called so
+// The amount of height (in pixels) that we factor in when jumpEnd is called so
 // that we show a little bit of the post text even on mobile devices instead of
 // scrolling to "suggested topics".
 const JUMP_END_BUFFER = 250;
diff --git a/app/assets/javascripts/discourse/app/lib/user-search.js b/app/assets/javascripts/discourse/app/lib/user-search.js
index 980d92a417a..1c90808b21b 100644
--- a/app/assets/javascripts/discourse/app/lib/user-search.js
+++ b/app/assets/javascripts/discourse/app/lib/user-search.js
@@ -157,7 +157,7 @@ function organizeResults(r, options) {
   return results;
 }
 
-// all punctuations except for -, _ and . which are allowed in usernames
+// all punctuation except for -, _ and . which are allowed in usernames
 // note: these are valid in names, but will end up tripping search anyway so just skip
 // this means searching for `sam saffron` is OK but if my name is `sam$ saffron` autocomplete
 // will not find me, which is a reasonable compromise
diff --git a/app/assets/javascripts/discourse/app/lib/utilities.js b/app/assets/javascripts/discourse/app/lib/utilities.js
index 5cb6976d5d0..9210d0607e0 100644
--- a/app/assets/javascripts/discourse/app/lib/utilities.js
+++ b/app/assets/javascripts/discourse/app/lib/utilities.js
@@ -452,9 +452,9 @@ const CODE_BLOCKS_REGEX = /^(    |\t).*|`[^`]+`|^```[^]*?^```|\[code\][^]*?\[\/c
 //                               |         |          |                  |
 //                               |         |          |       code blocks between [code]
 //                               |         |          |
-//                               |         |          +--- code blocks between three backquote
+//                               |         |          +--- code blocks between three backticks
 //                               |         |
-//                               |         +----- inline code between backquotes
+//                               |         +----- inline code between backticks
 //                               |
 //                               +------- paragraphs starting with 4 spaces or tab
 
diff --git a/app/assets/javascripts/discourse/app/lib/webauthn.js b/app/assets/javascripts/discourse/app/lib/webauthn.js
index e33ffc20019..113ef3c06bb 100644
--- a/app/assets/javascripts/discourse/app/lib/webauthn.js
+++ b/app/assets/javascripts/discourse/app/lib/webauthn.js
@@ -42,7 +42,7 @@ export function getWebauthnCredential(
         timeout: 60000,
 
         // see https://chromium.googlesource.com/chromium/src/+/master/content/browser/webauth/uv_preferred.md for why
-        // default value of preferred is not necesarrily what we want, it limits webauthn to only devices that support
+        // default value of preferred is not necessarily what we want, it limits webauthn to only devices that support
         // user verification, which usually requires entering a PIN
         userVerification: "discouraged",
       },
diff --git a/app/assets/javascripts/discourse/app/models/category.js b/app/assets/javascripts/discourse/app/models/category.js
index 4de28e476d4..af65076dba4 100644
--- a/app/assets/javascripts/discourse/app/models/category.js
+++ b/app/assets/javascripts/discourse/app/models/category.js
@@ -426,7 +426,7 @@ Category.reopenClass({
 
   findBySlugPathWithID(slugPathWithID) {
     let parts = slugPathWithID.split("/").filter(Boolean);
-    // slugs found by star/glob pathing in emeber do not automatically url decode - ensure that these are decoded
+    // slugs found by star/glob pathing in ember do not automatically url decode - ensure that these are decoded
     if (this.slugEncoded()) {
       parts = parts.map((urlPart) => decodeURI(urlPart));
     }
diff --git a/app/assets/javascripts/discourse/app/widgets/post-cooked.js b/app/assets/javascripts/discourse/app/widgets/post-cooked.js
index bbc669ac224..1526ec08743 100644
--- a/app/assets/javascripts/discourse/app/widgets/post-cooked.js
+++ b/app/assets/javascripts/discourse/app/widgets/post-cooked.js
@@ -155,7 +155,7 @@ export default class PostCooked {
           valid = href.split("?")[0] === lc.url;
         }
 
-        // don't display badge counts on category badge & oneboxes (unless when explicitely stated)
+        // don't display badge counts on category badge & oneboxes (unless when explicitly stated)
         if (valid && isValidLink($link)) {
           const title = I18n.t("topic_map.clicks", { count: lc.clicks });
           $link.append(
diff --git a/app/assets/javascripts/discourse/lib/translation-plugin.js b/app/assets/javascripts/discourse/lib/translation-plugin.js
index 5b9d06693e1..cc448934501 100644
--- a/app/assets/javascripts/discourse/lib/translation-plugin.js
+++ b/app/assets/javascripts/discourse/lib/translation-plugin.js
@@ -18,7 +18,7 @@ class TranslationPlugin extends Plugin {
 
   build() {
     // We could get fancy eventually and do this based on whether the yaml
-    // or vendor files change but in practice we should't need exact up to date
+    // or vendor files change but in practice we shouldn't need exact up to date
     // translations in admin.
     if (built) {
       return;
diff --git a/app/assets/javascripts/discourse/tests/acceptance/admin-badges-show-test.js b/app/assets/javascripts/discourse/tests/acceptance/admin-badges-show-test.js
index 3da3a7a4806..8670f9aeea0 100644
--- a/app/assets/javascripts/discourse/tests/acceptance/admin-badges-show-test.js
+++ b/app/assets/javascripts/discourse/tests/acceptance/admin-badges-show-test.js
@@ -95,7 +95,7 @@ acceptance("Admin - Badges - Show", function (needs) {
 
     await click("input#badge-icon");
     assert.ok(exists(".icon-picker"), "icon picker is becomes visible");
-    assert.ok(!exists(".image-uploader"), "image uploader bcomes hidden");
+    assert.ok(!exists(".image-uploader"), "image uploader becomes hidden");
     assert.equal(query(".icon-picker").textContent.trim(), "fa-rocket");
   });
 });
diff --git a/app/assets/javascripts/discourse/tests/acceptance/composer-test.js b/app/assets/javascripts/discourse/tests/acceptance/composer-test.js
index f60b38f3d67..45035e01fe8 100644
--- a/app/assets/javascripts/discourse/tests/acceptance/composer-test.js
+++ b/app/assets/javascripts/discourse/tests/acceptance/composer-test.js
@@ -788,7 +788,7 @@ acceptance("Composer", function (needs) {
       "![test|690x313, 50%](upload://test.png)",
       // 3 No dimensions, should not work
       "![test](upload://test.jpeg)",
-      // 4 Wrapped in backquetes should not work
+      // 4 Wrapped in backticks should not work
       "`![test|690x313](upload://test.png)`",
       // 5 html image - should not work
       "<img src='/images/avatar.png' wight='20' height='20'>",
diff --git a/app/assets/javascripts/discourse/tests/acceptance/group-index-test.js b/app/assets/javascripts/discourse/tests/acceptance/group-index-test.js
index f9a6ef32423..93a463a8d7a 100644
--- a/app/assets/javascripts/discourse/tests/acceptance/group-index-test.js
+++ b/app/assets/javascripts/discourse/tests/acceptance/group-index-test.js
@@ -27,7 +27,7 @@ acceptance("Group Members - Anonymous", function () {
     assert.equal(
       queryAll(".group-username-filter").attr("placeholder"),
       I18n.t("groups.members.filter_placeholder"),
-      "it should display the right filter placehodler"
+      "it should display the right filter placeholder"
     );
   });
 });
@@ -65,7 +65,7 @@ acceptance("Group Members", function (needs) {
     assert.equal(
       queryAll(".group-username-filter").attr("placeholder"),
       I18n.t("groups.members.filter_placeholder_admin"),
-      "it should display the right filter placehodler"
+      "it should display the right filter placeholder"
     );
   });
 
diff --git a/app/assets/javascripts/discourse/tests/fixtures/discovery-fixtures.js b/app/assets/javascripts/discourse/tests/fixtures/discovery-fixtures.js
index 1a15885b8d0..5267a5b2bbc 100644
--- a/app/assets/javascripts/discourse/tests/fixtures/discovery-fixtures.js
+++ b/app/assets/javascripts/discourse/tests/fixtures/discovery-fixtures.js
@@ -129,7 +129,7 @@ export default {
       { id: 6680, username: "cdman", avatar_template: "/images/avatar.png" },
       { id: 500, username: "aeid", avatar_template: "/images/avatar.png" },
       { id: 8, username: "geek", avatar_template: "/images/avatar.png" },
-      { id: 606, username: "Cafeine", avatar_template: "/images/avatar.png" }
+      { id: 606, username: "Caffeine", avatar_template: "/images/avatar.png" }
     ],
     topic_list: {
       can_create_topic: false,
@@ -1272,7 +1272,7 @@ export default {
       { id: 6680, username: "cdman", avatar_template: "/images/avatar.png" },
       { id: 500, username: "aeid", avatar_template: "/images/avatar.png" },
       { id: 8, username: "geek", avatar_template: "/images/avatar.png" },
-      { id: 606, username: "Cafeine", avatar_template: "/images/avatar.png" }
+      { id: 606, username: "Caffeine", avatar_template: "/images/avatar.png" }
     ],
     topic_list: {
       can_create_topic: false,
@@ -3003,7 +3003,7 @@ export default {
       { id: 3681, username: "Ajarn", avatar_template: "/images/avatar.png" },
       { id: 1621, username: "bnb", avatar_template: "/images/avatar.png" },
       { id: 6266, username: "bragi", avatar_template: "/images/avatar.png" },
-      { id: 5335, username: "masda70", avatar_template: "/images/avatar.png" },
+      { id: 5335, username: "mazda70", avatar_template: "/images/avatar.png" },
       {
         id: 6314,
         username: "rafaelfranca",
@@ -4183,7 +4183,7 @@ export default {
       { id: 3681, username: "Ajarn", avatar_template: "/images/avatar.png" },
       { id: 1621, username: "bnb", avatar_template: "/images/avatar.png" },
       { id: 6266, username: "bragi", avatar_template: "/images/avatar.png" },
-      { id: 5335, username: "masda70", avatar_template: "/images/avatar.png" },
+      { id: 5335, username: "mazda70", avatar_template: "/images/avatar.png" },
       {
         id: 6314,
         username: "rafaelfranca",
@@ -5255,7 +5255,7 @@ export default {
       { id: 3681, username: "Ajarn", avatar_template: "/images/avatar.png" },
       { id: 1621, username: "bnb", avatar_template: "/images/avatar.png" },
       { id: 6266, username: "bragi", avatar_template: "/images/avatar.png" },
-      { id: 5335, username: "masda70", avatar_template: "/images/avatar.png" },
+      { id: 5335, username: "mazda70", avatar_template: "/images/avatar.png" },
       {
         id: 6314,
         username: "rafaelfranca",
diff --git a/app/assets/javascripts/discourse/tests/fixtures/search-fixtures.js b/app/assets/javascripts/discourse/tests/fixtures/search-fixtures.js
index 9c6069291a1..0ece7ac6305 100644
--- a/app/assets/javascripts/discourse/tests/fixtures/search-fixtures.js
+++ b/app/assets/javascripts/discourse/tests/fixtures/search-fixtures.js
@@ -159,7 +159,7 @@ export default {
         uploaded_avatar_id: 3281,
         created_at: "2014-04-12T22:22:07.930Z",
         cooked:
-          '<p>So you want to set up Discourse on Ubuntu to hack on and develop with?</p>\n\n<p>We\'ll assume that you don\'t have Ruby/Rails/Postgre/Redis installed on your Ubuntu system. Let\'s begin!</p>\n\n<p><em>Although this guide assumes that you are using Ubuntu, but the set-up instructions will work fine for any Debian based ditribution.</em></p>\n\n<p><em>(If you want to install Discourse for production use, see <a href="https://github.com/discourse/discourse/blob/master/docs/INSTALL.md">our install guide</a>)</em></p>\n\n<h2>Install Discourse Dependencies</h2>\n\n<p>Run <a href="https://github.com/techAPJ/install-rails/blob/master/linux">this script</a> in terminal, to setup Rails development environment:</p>\n\n<pre><code>bash &lt;(wget -qO- https://raw.githubusercontent.com/techAPJ/install-rails/master/linux)</code></pre>\n\n<p><div class="lightbox-wrapper"><a href="//meta-s3-cdn.global.ssl.fastly.net/original/2X/9/9df737ab44032f2f671ac15513456bc668314591.png" class="lightbox" title="linux_script.png"><img src="//discourse-meta.s3-us-west-1.amazonaws.com/optimized/2X/9/9df737ab44032f2f671ac15513456bc668314591_1_690x189.png" width="690" height="189"><div class="meta">\n<span class="filename">linux_script.png</span><span class="informations">770x211 9.62 KB</span><span class="expand"></span>\n</div></a></div> </p>\n\n<p>This will install following new packages on your system:</p>\n\n<ul>\n<li><a href="http://git-scm.com/">Git</a></li>\n<li><a href="https://github.com/sstephenson/rbenv">rbenv</a></li>\n<li><a href="https://github.com/sstephenson/ruby-build">ruby-build</a></li>\n<li>\n<a href="https://www.ruby-lang.org/">Ruby</a> (stable)</li>\n<li><a href="http://rubyonrails.org/">Rails</a></li>\n<li><a href="http://www.postgresql.org/">PostgreSQL</a></li>\n<li><a href="https://sqlite.org/">SQLite</a></li>\n<li><a href="http://redis.io/">Redis</a></li>\n<li><a href="http://bundler.io/">Bundler</a></li>\n<li><a href="http://www.imagemagick.org/">ImageMagick</a></li>\n</ul>\n\n<p>Install Phantomjs:</p>\n\n<p>For 32 bit macine:</p>\n\n<pre><code>cd /usr/local/share\nsudo wget https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-1.9.8-linux-i686.tar.bz2\nsudo tar xvf phantomjs-1.9.8-linux-i686.tar.bz2\nsudo rm phantomjs-1.9.8-linux-i686.tar.bz2\nsudo ln -s /usr/local/share/phantomjs-1.9.8-linux-i686/bin/phantomjs /usr/local/bin/phantomjs\ncd</code></pre>\n\n<p>For 64 bit machine:</p>\n\n<pre><code>cd /usr/local/share\nsudo wget https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-1.9.8-linux-x86_64.tar.bz2\nsudo tar xvf phantomjs-1.9.8-linux-x86_64.tar.bz2\nsudo rm phantomjs-1.9.8-linux-x86_64.tar.bz2\nsudo ln -s /usr/local/share/phantomjs-1.9.8-linux-x86_64/bin/phantomjs /usr/local/bin/phantomjs\ncd</code></pre>\n\n<p><div class="lightbox-wrapper"><a href="//meta-s3-cdn.global.ssl.fastly.net/original/2X/0/0781669e092e0bdc29f8ec1830193503e884fd56.png" class="lightbox" title="phantomjs.png"><img src="//discourse-meta.s3-us-west-1.amazonaws.com/optimized/2X/0/0781669e092e0bdc29f8ec1830193503e884fd56_1_690x121.png" width="690" height="121"><div class="meta">\n<span class="filename">phantomjs.png</span><span class="informations">969x171 10.1 KB</span><span class="expand"></span>\n</div></a></div> </p>\n\n<p><em>In case you have any of this package pre-installed and don\'t want to run entire script, see the <a href="https://github.com/techAPJ/install-rails/blob/master/linux">script</a> and pick the packages you don\'t have currently installed. The script is fine-tuned for Discourse, and includes all the packages required for Discourse installation.</em></p>\n\n<p>Now that we have installed Discourse dependencies, let\'s move on to install Discourse itself.</p>\n\n<h2>Clone Discourse</h2>\n\n<p>Clone the Discourse repository in <code>~/discourse</code> folder:</p>\n\n<pre><code>git clone https://github.com/discourse/discourse.git ~/discourse</code></pre>\n\n<p><div class="lightbox-wrapper"><a href="//meta-s3-cdn.global.ssl.fastly.net/original/2X/2/23578e144aa4c37d7e577d570d34789add1078f1.png" class="lightbox" title="git_clone.png"><img src="//discourse-meta.s3-us-west-1.amazonaws.com/optimized/2X/2/23578e144aa4c37d7e577d570d34789add1078f1_1_690x97.png" width="690" height="97"><div class="meta">\n<span class="filename">git_clone.png</span><span class="informations">967x137 7.73 KB</span><span class="expand"></span>\n</div></a></div> </p>\n\n<h2>Setup Database</h2>\n\n<p>Open psql prompt as postgre user</p>\n\n<pre><code>sudo -u postgres psql postgres</code></pre>\n\n<p><div class="lightbox-wrapper"><a href="//meta-s3-cdn.global.ssl.fastly.net/original/2X/1/1cb9e5198b2695904204c2b1434427b610468610.png" class="lightbox" title="pg.png"><img src="//discourse-meta.s3-us-west-1.amazonaws.com/optimized/2X/1/1cb9e5198b2695904204c2b1434427b610468610_1_690x177.png" width="690" height="177"><div class="meta">\n<span class="filename">pg.png</span><span class="informations">725x187 5.79 KB</span><span class="expand"></span>\n</div></a></div> </p>\n\n<p>Create role <strong>with the same name as your ubuntu system username</strong> with <em>discourse</em> as password:</p>\n\n<pre><code>CREATE ROLE discourse WITH LOGIN ENCRYPTED PASSWORD \'discourse\' CREATEDB SUPERUSER;</code></pre>\n\n<p>In the above command, I named the role as <strong>discourse</strong>, this means that my ubuntu system username is <strong>discourse</strong>. (<em>It is necessary for role name to be same as system username, otherwise migrations will not run</em>)</p>\n\n<p>Check that you have successfully created <strong>discourse</strong> role:</p>\n\n<pre><code>\\du</code></pre>\n\n<p><div class="lightbox-wrapper"><a href="//meta-s3-cdn.global.ssl.fastly.net/original/2X/6/60439a04daa4efc8756a9528873cffb61c327bee.png" class="lightbox" title="pg_user.png"><img src="//discourse-meta.s3-us-west-1.amazonaws.com/optimized/2X/6/60439a04daa4efc8756a9528873cffb61c327bee_1_690x176.png" width="690" height="176"><div class="meta">\n<span class="filename">pg_user.png</span><span class="informations">725x185 7.5 KB</span><span class="expand"></span>\n</div></a></div> </p>\n\n<p>Create <strong>discourse_development</strong> and <strong>discourse_test</strong> database:</p>\n\n<pre><code>CREATE DATABASE discourse_development WITH OWNER discourse ENCODING \'UTF8\' TEMPLATE template0;\nCREATE DATABASE discourse_test WITH OWNER discourse ENCODING \'UTF8\' TEMPLATE template0;</code></pre>\n\n<p><div class="lightbox-wrapper"><a href="//meta-s3-cdn.global.ssl.fastly.net/original/2X/1/183b46c7f1ffaa024e7c99884fbcc022da2c91b4.png" class="lightbox" title="pg_db.png"><img src="//discourse-meta.s3-us-west-1.amazonaws.com/optimized/2X/1/183b46c7f1ffaa024e7c99884fbcc022da2c91b4_1_690x136.png" width="690" height="136"><div class="meta">\n<span class="filename">pg_db.png</span><span class="informations">724x143 6.82 KB</span><span class="expand"></span>\n</div></a></div> </p>\n\n<p>Exit psql prompt by pressing <kbd>ctrl</kbd><kbd>d</kbd></p>\n\n<p>Now access psql prompt in <strong>discourse_development</strong> database as <strong>discourse</strong> user:</p>\n\n<pre><code>psql -d discourse_development -U discourse -h localhost</code></pre>\n\n<p>When prompted for password, provide the password which you set at the time of creating role, if you followed the guide as is, the password is <strong>discourse</strong></p>\n\n<p>Run following commands, separately:</p>\n\n<pre><code>CREATE EXTENSION pg_trgm;\nCREATE EXTENSION hstore;</code></pre>\n\n<p><div class="lightbox-wrapper"><a href="//meta-s3-cdn.global.ssl.fastly.net/original/2X/0/04f4c1e4b3dd8ea1d183f653a77d35baca8c1201.png" class="lightbox" title="pg_dev.png"><img src="//discourse-meta.s3-us-west-1.amazonaws.com/optimized/2X/0/04f4c1e4b3dd8ea1d183f653a77d35baca8c1201_1_690x300.png" width="690" height="300"><div class="meta">\n<span class="filename">pg_dev.png</span><span class="informations">726x316 13.4 KB</span><span class="expand"></span>\n</div></a></div></p>\n\n<p>Exit psql prompt by pressing <kbd>ctrl</kbd><kbd>d</kbd></p>\n\n<p>Now access psql prompt in <strong>discourse_test</strong> database as <strong>discourse</strong> user:</p>\n\n<pre><code>psql -d discourse_test -U discourse -h localhost</code></pre>\n\n<p>When prompted for password, provide the password which you set at the time of creating role, if you followed the guide as is, the password is <strong>discourse</strong></p>\n\n<p>Run following commands, separately:</p>\n\n<pre><code>CREATE EXTENSION pg_trgm;\nCREATE EXTENSION hstore;</code></pre>\n\n<p><div class="lightbox-wrapper"><a href="//meta-s3-cdn.global.ssl.fastly.net/original/2X/d/d2a25de9f227831bf66107ab2ddc1a7abafca2f4.png" class="lightbox" title="pg_test.png"><img src="//discourse-meta.s3-us-west-1.amazonaws.com/optimized/2X/d/d2a25de9f227831bf66107ab2ddc1a7abafca2f4_1_690x302.png" width="690" height="302"><div class="meta">\n<span class="filename">pg_test.png</span><span class="informations">726x318 12.9 KB</span><span class="expand"></span>\n</div></a></div> </p>\n\n<p>Exit psql prompt by pressing <kbd>ctrl</kbd><kbd>d</kbd></p>\n\n<p>You have set-up the database successfully!</p>\n\n<h2>Bootstrap Discourse</h2>\n\n<p>Switch to your Discourse folder:</p>\n\n<pre><code>cd ~/discourse</code></pre>\n\n<p>Install the needed gems</p>\n\n<pre><code>bundle install</code></pre>\n\n<p><div class="lightbox-wrapper"><a href="//meta-s3-cdn.global.ssl.fastly.net/original/2X/e/e1e8390c232c20f6b532c80927cec07185a8e556.png" class="lightbox" title="bundle.png"><img src="//discourse-meta.s3-us-west-1.amazonaws.com/optimized/2X/e/e1e8390c232c20f6b532c80927cec07185a8e556_1_690x236.png" width="690" height="236"><div class="meta">\n<span class="filename">bundle.png</span><span class="informations">724x248 9.75 KB</span><span class="expand"></span>\n</div></a></div> </p>\n\n<p>Now that you have successfully configured database connection, run this command:</p>\n\n<pre><code>bundle exec rake db:migrate db:test:prepare db:seed_fu</code></pre>\n\n<p>Now, try running the specs: </p>\n\n<pre><code>bundle exec rake autospec</code></pre>\n\n<p><div class="lightbox-wrapper"><a href="//meta-s3-cdn.global.ssl.fastly.net/original/2X/8/8a645e90108980cea7fa06a524ecbf1558e142f1.png" class="lightbox" title="specs.png"><img src="//discourse-meta.s3-us-west-1.amazonaws.com/optimized/2X/8/8a645e90108980cea7fa06a524ecbf1558e142f1_1_690x253.png" width="690" height="253"><div class="meta">\n<span class="filename">specs.png</span><span class="informations">717x263 8.63 KB</span><span class="expand"></span>\n</div></a></div> </p>\n\n<p>Start rails server:</p>\n\n<pre><code>bundle exec rails server</code></pre>\n\n<p><div class="lightbox-wrapper"><a href="//meta-s3-cdn.global.ssl.fastly.net/original/2X/a/a8e7892e23bbfe3e613ebc6062605989de83310c.png" class="lightbox" title="server.png"><img src="//discourse-meta.s3-us-west-1.amazonaws.com/optimized/2X/a/a8e7892e23bbfe3e613ebc6062605989de83310c_1_690x218.png" width="690" height="218"><div class="meta">\n<span class="filename">server.png</span><span class="informations">724x229 10.8 KB</span><span class="expand"></span>\n</div></a></div> </p>\n\n<p>You should now be able to connect to discourse app on <a href="http://localhost:3000">http://localhost:3000</a> - try it out!</p>\n\n<p><div class="lightbox-wrapper"><a href="//meta-s3-cdn.global.ssl.fastly.net/original/2X/3/3f2fbcd03c5a30b08c51155130418085da77744e.png" class="lightbox" title="discourse_start.png"><img src="//discourse-meta.s3-us-west-1.amazonaws.com/optimized/2X/3/3f2fbcd03c5a30b08c51155130418085da77744e_1_690x188.png" width="690" height="188"><div class="meta">\n<span class="filename">discourse_start.png</span><span class="informations">1919x525 20.3 KB</span><span class="expand"></span>\n</div></a></div> </p>\n\n<h2>Configure Mail and Create New Account</h2>\n\n<p>We will use <a href="http://mailcatcher.me/">MailCatcher</a> to serve emails in development environment. Install and run MailCatcher:</p>\n\n<pre><code>gem install mailcatcher\nmailcatcher --http-ip 0.0.0.0</code></pre>\n\n<p>Create new account:</p>\n\n<p><div class="lightbox-wrapper"><a href="//meta-s3-cdn.global.ssl.fastly.net/original/3X/1/d/1d2e710b0865e78868c74d6cc54f96d1e2eb9303.png" class="lightbox" title="create_account.png"><img src="//discourse-meta.s3-us-west-1.amazonaws.com/optimized/3X/1/d/1d2e710b0865e78868c74d6cc54f96d1e2eb9303_1_690x384.png" width="690" height="384"><div class="meta">\n<span class="filename">create_account.png</span><span class="informations">720x401 13.5 KB</span><span class="expand"></span>\n</div></a></div> </p>\n\n<p>Check confirmation email by going to MailCatcher web interface at <a href="http://localhost:1080/">http://localhost:1080/</a></p>\n\n<p><div class="lightbox-wrapper"><a href="//meta-s3-cdn.global.ssl.fastly.net/original/3X/2/9/292a2cb247b37770cf4506f8745fdc39753e547e.png" class="lightbox" title="mc_sign_up_email.png"><img src="//discourse-meta.s3-us-west-1.amazonaws.com/optimized/3X/2/9/292a2cb247b37770cf4506f8745fdc39753e547e_1_690x172.png" width="690" height="172"><div class="meta">\n<span class="filename">mc_sign_up_email.png</span><span class="informations">1919x480 21.5 KB</span><span class="expand"></span>\n</div></a></div> </p>\n\n<p><em>If you did not receive the email, try running this in console</em>: <code>bundle exec sidekiq -q default</code></p>\n\n<p>Click the confirmation link and your account will be activated!</p>\n\n<p><div class="lightbox-wrapper"><a href="//meta-s3-cdn.global.ssl.fastly.net/original/2X/8/8fc06df9b084b4535bcafaaef675799d6ad3e5c9.png" class="lightbox" title="disc_normal_acc.png"><img src="//discourse-meta.s3-us-west-1.amazonaws.com/optimized/2X/8/8fc06df9b084b4535bcafaaef675799d6ad3e5c9_1_690x154.png" width="690" height="154"><div class="meta">\n<span class="filename">disc_normal_acc.png</span><span class="informations">1919x430 21.8 KB</span><span class="expand"></span>\n</div></a></div> </p>\n\n<h2>Access Admin</h2>\n\n<p>Now, to make your account as admin, run the following commands in rails console:</p>\n\n<pre><code>RAILS_ENV=development bundle exec rails c\nu = User.last\nu.admin = true\nu.save</code></pre>\n\n<p><div class="lightbox-wrapper"><a href="//meta-s3-cdn.global.ssl.fastly.net/original/2X/a/aa5478bc48ef8fef622e09e7948abb8ad8218000.png" class="lightbox" title="admin_console.png"><img src="//discourse-meta.s3-us-west-1.amazonaws.com/optimized/2X/a/aa5478bc48ef8fef622e09e7948abb8ad8218000_1_690x441.png" width="690" height="441"><div class="meta">\n<span class="filename">admin_console.png</span><span class="informations">722x462 31.7 KB</span><span class="expand"></span>\n</div></a></div> </p>\n\n<p>Once you execute the above commands successfully, check out your Discourse account again:</p>\n\n<p><div class="lightbox-wrapper"><a href="//meta-s3-cdn.global.ssl.fastly.net/original/2X/7/72840ed4dbbc02544471649ee4eaa272fde205ef.png" class="lightbox" title="admin_success.png"><img src="//discourse-meta.s3-us-west-1.amazonaws.com/optimized/2X/7/72840ed4dbbc02544471649ee4eaa272fde205ef_1_690x371.png" width="690" height="371"><div class="meta">\n<span class="filename">admin_success.png</span><span class="informations">1919x1032 30.3 KB</span><span class="expand"></span>\n</div></a></div> </p>\n\n<p>Congratulations! You are now the admin of your own Discourse installation!</p>\n\n<p>Happy hacking!</p>\n\n<p>If anything needs to be improved in this guide, feel free to ask on <a href="https://meta.discourse.org/t/developers-guide-to-install-discourse-on-ubuntu/14727">meta.discourse.org</a>, or even better, submit a <a href="https://github.com/techAPJ/discourse-development-ubuntu">pull request</a>.</p>',
+          '<p>So you want to set up Discourse on Ubuntu to hack on and develop with?</p>\n\n<p>We\'ll assume that you don\'t have Ruby/Rails/Postgre/Redis installed on your Ubuntu system. Let\'s begin!</p>\n\n<p><em>Although this guide assumes that you are using Ubuntu, but the set-up instructions will work fine for any Debian based distribution.</em></p>\n\n<p><em>(If you want to install Discourse for production use, see <a href="https://github.com/discourse/discourse/blob/master/docs/INSTALL.md">our install guide</a>)</em></p>\n\n<h2>Install Discourse Dependencies</h2>\n\n<p>Run <a href="https://github.com/techAPJ/install-rails/blob/master/linux">this script</a> in terminal, to setup Rails development environment:</p>\n\n<pre><code>bash &lt;(wget -qO- https://raw.githubusercontent.com/techAPJ/install-rails/master/linux)</code></pre>\n\n<p><div class="lightbox-wrapper"><a href="//meta-s3-cdn.global.ssl.fastly.net/original/2X/9/9df737ab44032f2f671ac15513456bc668314591.png" class="lightbox" title="linux_script.png"><img src="//discourse-meta.s3-us-west-1.amazonaws.com/optimized/2X/9/9df737ab44032f2f671ac15513456bc668314591_1_690x189.png" width="690" height="189"><div class="meta">\n<span class="filename">linux_script.png</span><span class="informations">770x211 9.62 KB</span><span class="expand"></span>\n</div></a></div> </p>\n\n<p>This will install following new packages on your system:</p>\n\n<ul>\n<li><a href="http://git-scm.com/">Git</a></li>\n<li><a href="https://github.com/sstephenson/rbenv">rbenv</a></li>\n<li><a href="https://github.com/sstephenson/ruby-build">ruby-build</a></li>\n<li>\n<a href="https://www.ruby-lang.org/">Ruby</a> (stable)</li>\n<li><a href="http://rubyonrails.org/">Rails</a></li>\n<li><a href="http://www.postgresql.org/">PostgreSQL</a></li>\n<li><a href="https://sqlite.org/">SQLite</a></li>\n<li><a href="http://redis.io/">Redis</a></li>\n<li><a href="http://bundler.io/">Bundler</a></li>\n<li><a href="http://www.imagemagick.org/">ImageMagick</a></li>\n</ul>\n\n<p>Install Phantomjs:</p>\n\n<p>For 32 bit machine:</p>\n\n<pre><code>cd /usr/local/share\nsudo wget https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-1.9.8-linux-i686.tar.bz2\nsudo tar xvf phantomjs-1.9.8-linux-i686.tar.bz2\nsudo rm phantomjs-1.9.8-linux-i686.tar.bz2\nsudo ln -s /usr/local/share/phantomjs-1.9.8-linux-i686/bin/phantomjs /usr/local/bin/phantomjs\ncd</code></pre>\n\n<p>For 64 bit machine:</p>\n\n<pre><code>cd /usr/local/share\nsudo wget https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-1.9.8-linux-x86_64.tar.bz2\nsudo tar xvf phantomjs-1.9.8-linux-x86_64.tar.bz2\nsudo rm phantomjs-1.9.8-linux-x86_64.tar.bz2\nsudo ln -s /usr/local/share/phantomjs-1.9.8-linux-x86_64/bin/phantomjs /usr/local/bin/phantomjs\ncd</code></pre>\n\n<p><div class="lightbox-wrapper"><a href="//meta-s3-cdn.global.ssl.fastly.net/original/2X/0/0781669e092e0bdc29f8ec1830193503e884fd56.png" class="lightbox" title="phantomjs.png"><img src="//discourse-meta.s3-us-west-1.amazonaws.com/optimized/2X/0/0781669e092e0bdc29f8ec1830193503e884fd56_1_690x121.png" width="690" height="121"><div class="meta">\n<span class="filename">phantomjs.png</span><span class="informations">969x171 10.1 KB</span><span class="expand"></span>\n</div></a></div> </p>\n\n<p><em>In case you have any of this package pre-installed and don\'t want to run entire script, see the <a href="https://github.com/techAPJ/install-rails/blob/master/linux">script</a> and pick the packages you don\'t have currently installed. The script is fine-tuned for Discourse, and includes all the packages required for Discourse installation.</em></p>\n\n<p>Now that we have installed Discourse dependencies, let\'s move on to install Discourse itself.</p>\n\n<h2>Clone Discourse</h2>\n\n<p>Clone the Discourse repository in <code>~/discourse</code> folder:</p>\n\n<pre><code>git clone https://github.com/discourse/discourse.git ~/discourse</code></pre>\n\n<p><div class="lightbox-wrapper"><a href="//meta-s3-cdn.global.ssl.fastly.net/original/2X/2/23578e144aa4c37d7e577d570d34789add1078f1.png" class="lightbox" title="git_clone.png"><img src="//discourse-meta.s3-us-west-1.amazonaws.com/optimized/2X/2/23578e144aa4c37d7e577d570d34789add1078f1_1_690x97.png" width="690" height="97"><div class="meta">\n<span class="filename">git_clone.png</span><span class="informations">967x137 7.73 KB</span><span class="expand"></span>\n</div></a></div> </p>\n\n<h2>Setup Database</h2>\n\n<p>Open psql prompt as postgre user</p>\n\n<pre><code>sudo -u postgres psql postgres</code></pre>\n\n<p><div class="lightbox-wrapper"><a href="//meta-s3-cdn.global.ssl.fastly.net/original/2X/1/1cb9e5198b2695904204c2b1434427b610468610.png" class="lightbox" title="pg.png"><img src="//discourse-meta.s3-us-west-1.amazonaws.com/optimized/2X/1/1cb9e5198b2695904204c2b1434427b610468610_1_690x177.png" width="690" height="177"><div class="meta">\n<span class="filename">pg.png</span><span class="informations">725x187 5.79 KB</span><span class="expand"></span>\n</div></a></div> </p>\n\n<p>Create role <strong>with the same name as your ubuntu system username</strong> with <em>discourse</em> as password:</p>\n\n<pre><code>CREATE ROLE discourse WITH LOGIN ENCRYPTED PASSWORD \'discourse\' CREATEDB SUPERUSER;</code></pre>\n\n<p>In the above command, I named the role as <strong>discourse</strong>, this means that my ubuntu system username is <strong>discourse</strong>. (<em>It is necessary for role name to be same as system username, otherwise migrations will not run</em>)</p>\n\n<p>Check that you have successfully created <strong>discourse</strong> role:</p>\n\n<pre><code>\\du</code></pre>\n\n<p><div class="lightbox-wrapper"><a href="//meta-s3-cdn.global.ssl.fastly.net/original/2X/6/60439a04daa4efc8756a9528873cffb61c327bee.png" class="lightbox" title="pg_user.png"><img src="//discourse-meta.s3-us-west-1.amazonaws.com/optimized/2X/6/60439a04daa4efc8756a9528873cffb61c327bee_1_690x176.png" width="690" height="176"><div class="meta">\n<span class="filename">pg_user.png</span><span class="informations">725x185 7.5 KB</span><span class="expand"></span>\n</div></a></div> </p>\n\n<p>Create <strong>discourse_development</strong> and <strong>discourse_test</strong> database:</p>\n\n<pre><code>CREATE DATABASE discourse_development WITH OWNER discourse ENCODING \'UTF8\' TEMPLATE template0;\nCREATE DATABASE discourse_test WITH OWNER discourse ENCODING \'UTF8\' TEMPLATE template0;</code></pre>\n\n<p><div class="lightbox-wrapper"><a href="//meta-s3-cdn.global.ssl.fastly.net/original/2X/1/183b46c7f1ffaa024e7c99884fbcc022da2c91b4.png" class="lightbox" title="pg_db.png"><img src="//discourse-meta.s3-us-west-1.amazonaws.com/optimized/2X/1/183b46c7f1ffaa024e7c99884fbcc022da2c91b4_1_690x136.png" width="690" height="136"><div class="meta">\n<span class="filename">pg_db.png</span><span class="informations">724x143 6.82 KB</span><span class="expand"></span>\n</div></a></div> </p>\n\n<p>Exit psql prompt by pressing <kbd>ctrl</kbd><kbd>d</kbd></p>\n\n<p>Now access psql prompt in <strong>discourse_development</strong> database as <strong>discourse</strong> user:</p>\n\n<pre><code>psql -d discourse_development -U discourse -h localhost</code></pre>\n\n<p>When prompted for password, provide the password which you set at the time of creating role, if you followed the guide as is, the password is <strong>discourse</strong></p>\n\n<p>Run following commands, separately:</p>\n\n<pre><code>CREATE EXTENSION pg_trgm;\nCREATE EXTENSION hstore;</code></pre>\n\n<p><div class="lightbox-wrapper"><a href="//meta-s3-cdn.global.ssl.fastly.net/original/2X/0/04f4c1e4b3dd8ea1d183f653a77d35baca8c1201.png" class="lightbox" title="pg_dev.png"><img src="//discourse-meta.s3-us-west-1.amazonaws.com/optimized/2X/0/04f4c1e4b3dd8ea1d183f653a77d35baca8c1201_1_690x300.png" width="690" height="300"><div class="meta">\n<span class="filename">pg_dev.png</span><span class="informations">726x316 13.4 KB</span><span class="expand"></span>\n</div></a></div></p>\n\n<p>Exit psql prompt by pressing <kbd>ctrl</kbd><kbd>d</kbd></p>\n\n<p>Now access psql prompt in <strong>discourse_test</strong> database as <strong>discourse</strong> user:</p>\n\n<pre><code>psql -d discourse_test -U discourse -h localhost</code></pre>\n\n<p>When prompted for password, provide the password which you set at the time of creating role, if you followed the guide as is, the password is <strong>discourse</strong></p>\n\n<p>Run following commands, separately:</p>\n\n<pre><code>CREATE EXTENSION pg_trgm;\nCREATE EXTENSION hstore;</code></pre>\n\n<p><div class="lightbox-wrapper"><a href="//meta-s3-cdn.global.ssl.fastly.net/original/2X/d/d2a25de9f227831bf66107ab2ddc1a7abafca2f4.png" class="lightbox" title="pg_test.png"><img src="//discourse-meta.s3-us-west-1.amazonaws.com/optimized/2X/d/d2a25de9f227831bf66107ab2ddc1a7abafca2f4_1_690x302.png" width="690" height="302"><div class="meta">\n<span class="filename">pg_test.png</span><span class="informations">726x318 12.9 KB</span><span class="expand"></span>\n</div></a></div> </p>\n\n<p>Exit psql prompt by pressing <kbd>ctrl</kbd><kbd>d</kbd></p>\n\n<p>You have set-up the database successfully!</p>\n\n<h2>Bootstrap Discourse</h2>\n\n<p>Switch to your Discourse folder:</p>\n\n<pre><code>cd ~/discourse</code></pre>\n\n<p>Install the needed gems</p>\n\n<pre><code>bundle install</code></pre>\n\n<p><div class="lightbox-wrapper"><a href="//meta-s3-cdn.global.ssl.fastly.net/original/2X/e/e1e8390c232c20f6b532c80927cec07185a8e556.png" class="lightbox" title="bundle.png"><img src="//discourse-meta.s3-us-west-1.amazonaws.com/optimized/2X/e/e1e8390c232c20f6b532c80927cec07185a8e556_1_690x236.png" width="690" height="236"><div class="meta">\n<span class="filename">bundle.png</span><span class="informations">724x248 9.75 KB</span><span class="expand"></span>\n</div></a></div> </p>\n\n<p>Now that you have successfully configured database connection, run this command:</p>\n\n<pre><code>bundle exec rake db:migrate db:test:prepare db:seed_fu</code></pre>\n\n<p>Now, try running the specs: </p>\n\n<pre><code>bundle exec rake autospec</code></pre>\n\n<p><div class="lightbox-wrapper"><a href="//meta-s3-cdn.global.ssl.fastly.net/original/2X/8/8a645e90108980cea7fa06a524ecbf1558e142f1.png" class="lightbox" title="specs.png"><img src="//discourse-meta.s3-us-west-1.amazonaws.com/optimized/2X/8/8a645e90108980cea7fa06a524ecbf1558e142f1_1_690x253.png" width="690" height="253"><div class="meta">\n<span class="filename">specs.png</span><span class="informations">717x263 8.63 KB</span><span class="expand"></span>\n</div></a></div> </p>\n\n<p>Start rails server:</p>\n\n<pre><code>bundle exec rails server</code></pre>\n\n<p><div class="lightbox-wrapper"><a href="//meta-s3-cdn.global.ssl.fastly.net/original/2X/a/a8e7892e23bbfe3e613ebc6062605989de83310c.png" class="lightbox" title="server.png"><img src="//discourse-meta.s3-us-west-1.amazonaws.com/optimized/2X/a/a8e7892e23bbfe3e613ebc6062605989de83310c_1_690x218.png" width="690" height="218"><div class="meta">\n<span class="filename">server.png</span><span class="informations">724x229 10.8 KB</span><span class="expand"></span>\n</div></a></div> </p>\n\n<p>You should now be able to connect to discourse app on <a href="http://localhost:3000">http://localhost:3000</a> - try it out!</p>\n\n<p><div class="lightbox-wrapper"><a href="//meta-s3-cdn.global.ssl.fastly.net/original/2X/3/3f2fbcd03c5a30b08c51155130418085da77744e.png" class="lightbox" title="discourse_start.png"><img src="//discourse-meta.s3-us-west-1.amazonaws.com/optimized/2X/3/3f2fbcd03c5a30b08c51155130418085da77744e_1_690x188.png" width="690" height="188"><div class="meta">\n<span class="filename">discourse_start.png</span><span class="informations">1919x525 20.3 KB</span><span class="expand"></span>\n</div></a></div> </p>\n\n<h2>Configure Mail and Create New Account</h2>\n\n<p>We will use <a href="http://mailcatcher.me/">MailCatcher</a> to serve emails in development environment. Install and run MailCatcher:</p>\n\n<pre><code>gem install mailcatcher\nmailcatcher --http-ip 0.0.0.0</code></pre>\n\n<p>Create new account:</p>\n\n<p><div class="lightbox-wrapper"><a href="//meta-s3-cdn.global.ssl.fastly.net/original/3X/1/d/1d2e710b0865e78868c74d6cc54f96d1e2eb9303.png" class="lightbox" title="create_account.png"><img src="//discourse-meta.s3-us-west-1.amazonaws.com/optimized/3X/1/d/1d2e710b0865e78868c74d6cc54f96d1e2eb9303_1_690x384.png" width="690" height="384"><div class="meta">\n<span class="filename">create_account.png</span><span class="informations">720x401 13.5 KB</span><span class="expand"></span>\n</div></a></div> </p>\n\n<p>Check confirmation email by going to MailCatcher web interface at <a href="http://localhost:1080/">http://localhost:1080/</a></p>\n\n<p><div class="lightbox-wrapper"><a href="//meta-s3-cdn.global.ssl.fastly.net/original/3X/2/9/292a2cb247b37770cf4506f8745fdc39753e547e.png" class="lightbox" title="mc_sign_up_email.png"><img src="//discourse-meta.s3-us-west-1.amazonaws.com/optimized/3X/2/9/292a2cb247b37770cf4506f8745fdc39753e547e_1_690x172.png" width="690" height="172"><div class="meta">\n<span class="filename">mc_sign_up_email.png</span><span class="informations">1919x480 21.5 KB</span><span class="expand"></span>\n</div></a></div> </p>\n\n<p><em>If you did not receive the email, try running this in console</em>: <code>bundle exec sidekiq -q default</code></p>\n\n<p>Click the confirmation link and your account will be activated!</p>\n\n<p><div class="lightbox-wrapper"><a href="//meta-s3-cdn.global.ssl.fastly.net/original/2X/8/8fc06df9b084b4535bcafaaef675799d6ad3e5c9.png" class="lightbox" title="disc_normal_acc.png"><img src="//discourse-meta.s3-us-west-1.amazonaws.com/optimized/2X/8/8fc06df9b084b4535bcafaaef675799d6ad3e5c9_1_690x154.png" width="690" height="154"><div class="meta">\n<span class="filename">disc_normal_acc.png</span><span class="informations">1919x430 21.8 KB</span><span class="expand"></span>\n</div></a></div> </p>\n\n<h2>Access Admin</h2>\n\n<p>Now, to make your account as admin, run the following commands in rails console:</p>\n\n<pre><code>RAILS_ENV=development bundle exec rails c\nu = User.last\nu.admin = true\nu.save</code></pre>\n\n<p><div class="lightbox-wrapper"><a href="//meta-s3-cdn.global.ssl.fastly.net/original/2X/a/aa5478bc48ef8fef622e09e7948abb8ad8218000.png" class="lightbox" title="admin_console.png"><img src="//discourse-meta.s3-us-west-1.amazonaws.com/optimized/2X/a/aa5478bc48ef8fef622e09e7948abb8ad8218000_1_690x441.png" width="690" height="441"><div class="meta">\n<span class="filename">admin_console.png</span><span class="informations">722x462 31.7 KB</span><span class="expand"></span>\n</div></a></div> </p>\n\n<p>Once you execute the above commands successfully, check out your Discourse account again:</p>\n\n<p><div class="lightbox-wrapper"><a href="//meta-s3-cdn.global.ssl.fastly.net/original/2X/7/72840ed4dbbc02544471649ee4eaa272fde205ef.png" class="lightbox" title="admin_success.png"><img src="//discourse-meta.s3-us-west-1.amazonaws.com/optimized/2X/7/72840ed4dbbc02544471649ee4eaa272fde205ef_1_690x371.png" width="690" height="371"><div class="meta">\n<span class="filename">admin_success.png</span><span class="informations">1919x1032 30.3 KB</span><span class="expand"></span>\n</div></a></div> </p>\n\n<p>Congratulations! You are now the admin of your own Discourse installation!</p>\n\n<p>Happy hacking!</p>\n\n<p>If anything needs to be improved in this guide, feel free to ask on <a href="https://meta.discourse.org/t/developers-guide-to-install-discourse-on-ubuntu/14727">meta.discourse.org</a>, or even better, submit a <a href="https://github.com/techAPJ/discourse-development-ubuntu">pull request</a>.</p>',
         post_number: 1,
         post_type: 1,
         updated_at: "2015-06-22T17:24:20.607Z",
diff --git a/app/assets/javascripts/discourse/tests/fixtures/topic.js b/app/assets/javascripts/discourse/tests/fixtures/topic.js
index 95debff3a28..70d5b2ff5c4 100644
--- a/app/assets/javascripts/discourse/tests/fixtures/topic.js
+++ b/app/assets/javascripts/discourse/tests/fixtures/topic.js
@@ -3091,11 +3091,11 @@ export default {
       {
         id: 27346,
         title:
-          'Reply+{messagekey}@... optionaly in header "from" in addition to "reply-to"',
+          'Reply+{messagekey}@... optionally in header "from" in addition to "reply-to"',
         fancy_title:
-          "Reply+{messagekey}@&hellip; optionaly in header &ldquo;from&rdquo; in addition to &ldquo;reply-to&rdquo;",
+          "Reply+{messagekey}@&hellip; optionally in header &ldquo;from&rdquo; in addition to &ldquo;reply-to&rdquo;",
         slug:
-          "reply-messagekey-optionaly-in-header-from-in-addition-to-reply-to",
+          "reply-messagekey-optionally-in-header-from-in-addition-to-reply-to",
         posts_count: 1,
         reply_count: 0,
         highest_post_number: 1,
diff --git a/app/assets/javascripts/discourse/tests/fixtures/user-fixtures.js b/app/assets/javascripts/discourse/tests/fixtures/user-fixtures.js
index 3fdf904693e..da0e300420c 100644
--- a/app/assets/javascripts/discourse/tests/fixtures/user-fixtures.js
+++ b/app/assets/javascripts/discourse/tests/fixtures/user-fixtures.js
@@ -1132,7 +1132,7 @@ export default {
         action_type: 6,
         created_at: "2014-01-13T21:58:28Z",
         excerpt:
-          "It looks uneeded, but you need to review a fair amount of code to confirm it is not needed.  \n\nI am going to keep it for now cause its safer under some weird edge conditions.",
+          "It looks unneeded, but you need to review a fair amount of code to confirm it is not needed.  \n\nI am going to keep it for now cause its safer under some weird edge conditions.",
         avatar_template:
           "//www.gravatar.com/avatar/3dcae8378d46c244172a115c28ca49ce.png?s={size}&r=pg&d=identicon",
         acting_avatar_template:
diff --git a/app/assets/javascripts/discourse/tests/integration/widgets/post-test.js b/app/assets/javascripts/discourse/tests/integration/widgets/post-test.js
index 708c59101dc..3e2cda1786e 100644
--- a/app/assets/javascripts/discourse/tests/integration/widgets/post-test.js
+++ b/app/assets/javascripts/discourse/tests/integration/widgets/post-test.js
@@ -526,7 +526,7 @@ discourseModule("Integration | Component | Widget | post", function (hooks) {
     },
   });
 
-  componentTest("reply directly above (supressed)", {
+  componentTest("reply directly above (suppressed)", {
     template: hbs`{{mount-widget widget="post" args=args}}`,
     beforeEach() {
       this.set("args", {
@@ -545,7 +545,7 @@ discourseModule("Integration | Component | Widget | post", function (hooks) {
     },
   });
 
-  componentTest("reply a few posts above (supressed)", {
+  componentTest("reply a few posts above (suppressed)", {
     template: hbs`{{mount-widget widget="post" args=args}}`,
     beforeEach() {
       this.set("args", {
diff --git a/app/assets/javascripts/discourse/tests/integration/widgets/small-user-list-test.js b/app/assets/javascripts/discourse/tests/integration/widgets/small-user-list-test.js
index 2cccac3306b..ac8dbcdaefa 100644
--- a/app/assets/javascripts/discourse/tests/integration/widgets/small-user-list-test.js
+++ b/app/assets/javascripts/discourse/tests/integration/widgets/small-user-list-test.js
@@ -25,7 +25,7 @@ discourseModule(
       async test(assert) {
         assert.ok(queryAll('[data-user-card="eviltrout"]').length === 1);
         assert.ok(queryAll('[data-user-card="someone"]').length === 0);
-        assert.ok(queryAll(".unknown").length, "includes unkown user");
+        assert.ok(queryAll(".unknown").length, "includes unknown user");
       },
     });
   }
diff --git a/app/assets/javascripts/discourse/tests/integration/widgets/widget-test.js b/app/assets/javascripts/discourse/tests/integration/widgets/widget-test.js
index e31e82e83c0..6df1ef695a8 100644
--- a/app/assets/javascripts/discourse/tests/integration/widgets/widget-test.js
+++ b/app/assets/javascripts/discourse/tests/integration/widgets/widget-test.js
@@ -305,7 +305,7 @@ discourseModule("Integration | Component | Widget | base", function (hooks) {
     },
 
     test(assert) {
-      // comin up
+      // coming up
       assert.equal(queryAll("span.string").text(), "evil");
       assert.equal(queryAll("span.var").text(), "trout");
       assert.equal(queryAll("a").prop("title"), "evil");
diff --git a/app/assets/javascripts/discourse/tests/setup-tests.js b/app/assets/javascripts/discourse/tests/setup-tests.js
index 7742a30bb15..12f93098ab1 100644
--- a/app/assets/javascripts/discourse/tests/setup-tests.js
+++ b/app/assets/javascripts/discourse/tests/setup-tests.js
@@ -247,7 +247,7 @@ function setupTestsCommon(application, container, config) {
 
     if (!setupApplicationTest) {
       // ensures any event not removed is not leaking between tests
-      // most likely in intialisers, other places (controller, component...)
+      // most likely in initializers, other places (controller, component...)
       // should be fixed in code
       clearAppEventsCache(getOwner(this));
     }
diff --git a/app/assets/javascripts/discourse/tests/unit/controllers/topic-test.js b/app/assets/javascripts/discourse/tests/unit/controllers/topic-test.js
index 7d4c273281c..6920e74a485 100644
--- a/app/assets/javascripts/discourse/tests/unit/controllers/topic-test.js
+++ b/app/assets/javascripts/discourse/tests/unit/controllers/topic-test.js
@@ -538,7 +538,7 @@ discourseModule("Unit | Controller | topic", function (hooks) {
         post: placeholder,
       }),
       null,
-      "it should work with a post-placehodler"
+      "it should work with a post-placeholder"
     );
   });
 
diff --git a/app/assets/javascripts/discourse/tests/unit/lib/pretty-text-test.js b/app/assets/javascripts/discourse/tests/unit/lib/pretty-text-test.js
index f413ffea754..f25c78ce879 100644
--- a/app/assets/javascripts/discourse/tests/unit/lib/pretty-text-test.js
+++ b/app/assets/javascripts/discourse/tests/unit/lib/pretty-text-test.js
@@ -1602,7 +1602,7 @@ var bar = 'bar';
     assert.cookedOptions(" -->asd", enabledTypographer, "<p>–&gt;asd</p>");
   });
 
-  test("default typhographic replacements", function (assert) {
+  test("default typographic replacements", function (assert) {
     const enabledTypographer = {
       siteSettings: { enable_markdown_typographer: true },
     };
@@ -1628,7 +1628,7 @@ var bar = 'bar';
     assert.cookedOptions("(pa) (PA)", enabledTypographer, "<p>¶ ¶</p>");
   });
 
-  test("default typhographic replacements - dashes", function (assert) {
+  test("default typographic replacements - dashes", function (assert) {
     const enabledTypographer = {
       siteSettings: { enable_markdown_typographer: true },
     };
@@ -1663,7 +1663,7 @@ var bar = 'bar';
     );
   });
 
-  test("disabled typhographic replacements", function (assert) {
+  test("disabled typographic replacements", function (assert) {
     const enabledTypographer = {
       siteSettings: { enable_markdown_typographer: true },
     };
diff --git a/app/assets/javascripts/discourse/tests/unit/lib/user-search-test.js b/app/assets/javascripts/discourse/tests/unit/lib/user-search-test.js
index 021fee33fc8..7e63f52ce79 100644
--- a/app/assets/javascripts/discourse/tests/unit/lib/user-search-test.js
+++ b/app/assets/javascripts/discourse/tests/unit/lib/user-search-test.js
@@ -129,7 +129,7 @@ module("Unit | Utility | user-search", function (hooks) {
     assert.equal(results[results.length - 1]["name"], "team");
   });
 
-  test("it skips a search depending on punctuations", async function (assert) {
+  test("it skips a search depending on punctuation", async function (assert) {
     let results;
     let skippedTerms = [
       "@sam  s", // double space is not allowed
diff --git a/app/assets/javascripts/discourse/tests/unit/models/composer-test.js b/app/assets/javascripts/discourse/tests/unit/models/composer-test.js
index 11be45dce16..415988c24f6 100644
--- a/app/assets/javascripts/discourse/tests/unit/models/composer-test.js
+++ b/app/assets/javascripts/discourse/tests/unit/models/composer-test.js
@@ -47,7 +47,7 @@ discourseModule("Unit | Model | composer", function () {
       2,
       "handles nested quotes correctly"
     );
-    replyLength("<!-- a commnent -->", 0, "remove comments");
+    replyLength("<!-- a comment -->", 0, "remove comments");
 
     replyLength(
       "<!-- a comment -->\n more text \n<!-- a comment -->",
@@ -333,7 +333,7 @@ discourseModule("Unit | Model | composer", function () {
     assert.equal(
       newComposer().get("replyDirty"),
       false,
-      "replyDirty is initally false with a quote"
+      "replyDirty is initially false with a quote"
     );
   });
 
diff --git a/app/assets/javascripts/discourse/tests/unit/models/post-stream-test.js b/app/assets/javascripts/discourse/tests/unit/models/post-stream-test.js
index 78151c33552..4fd2db7af21 100644
--- a/app/assets/javascripts/discourse/tests/unit/models/post-stream-test.js
+++ b/app/assets/javascripts/discourse/tests/unit/models/post-stream-test.js
@@ -826,7 +826,7 @@ module("Unit | Model | post-stream", function () {
     assert.ok(
       postStream.get("lastAppended"),
       found,
-      "comitting a post changes lastAppended"
+      "committing a post changes lastAppended"
     );
   });
 
@@ -885,7 +885,7 @@ module("Unit | Model | post-stream", function () {
     );
   });
 
-  test("comitting and triggerNewPostsInStream race condition", function (assert) {
+  test("committing and triggerNewPostsInStream race condition", function (assert) {
     const postStream = buildStream(4964);
     const store = postStream.store;
 
diff --git a/app/assets/javascripts/discourse/tests/unit/models/rest-model-test.js b/app/assets/javascripts/discourse/tests/unit/models/rest-model-test.js
index b549826f1ad..d444d275efe 100644
--- a/app/assets/javascripts/discourse/tests/unit/models/rest-model-test.js
+++ b/app/assets/javascripts/discourse/tests/unit/models/rest-model-test.js
@@ -50,7 +50,7 @@ module("Unit | Model | rest-model", function () {
     const secondPromise = widget.update({ name: "new name" });
 
     firstPromise.then(function () {
-      assert.ok(true, "the first promise succeeeds");
+      assert.ok(true, "the first promise succeeds");
     });
 
     secondPromise.catch(function () {
@@ -93,7 +93,7 @@ module("Unit | Model | rest-model", function () {
     const firstPromise = widget.save({ name: "Evil Widget" });
     const secondPromise = widget.save({ name: "Evil Widget" });
     firstPromise.then(function () {
-      assert.ok(true, "the first promise succeeeds");
+      assert.ok(true, "the first promise succeeds");
     });
 
     secondPromise.catch(function () {
@@ -127,7 +127,7 @@ module("Unit | Model | rest-model", function () {
     //Create
     const widget = store.createRecord("my-widget");
     await widget.save({ name: "Evil Widget" });
-    assert.equal(widget.id, 100, "it saved a new record successully");
+    assert.equal(widget.id, 100, "it saved a new record successfully");
     assert.equal(widget.get("name"), "Evil Widget");
 
     // Update
diff --git a/app/assets/javascripts/locales/i18n.js b/app/assets/javascripts/locales/i18n.js
index 814e8ed8d9d..24547305e3d 100644
--- a/app/assets/javascripts/locales/i18n.js
+++ b/app/assets/javascripts/locales/i18n.js
@@ -73,7 +73,7 @@ I18n.lookup = function(scope, options) {
   return messages;
 };
 
-// Merge serveral hash options, checking if value is set before
+// Merge several hash options, checking if value is set before
 // overwriting any value. The precedence is from left to right.
 //
 //   I18n.prepareOptions({name: "John Doe"}, {name: "Mary Doe", role: "user"});
diff --git a/app/assets/javascripts/pretty-text/addon/sanitizer.js b/app/assets/javascripts/pretty-text/addon/sanitizer.js
index 66bdcbf4ce2..45342882d56 100644
--- a/app/assets/javascripts/pretty-text/addon/sanitizer.js
+++ b/app/assets/javascripts/pretty-text/addon/sanitizer.js
@@ -97,7 +97,7 @@ export function sanitize(text, allowLister) {
         }
 
         if (tag === "video" && name === "autoplay") {
-          // This might give us duplicate 'muted' atttributes
+          // This might give us duplicate 'muted' attributes
           // but they will be deduped by later processing
           return "autoplay muted";
         }
diff --git a/app/assets/javascripts/pretty-text/engines/discourse-markdown/html-img.js b/app/assets/javascripts/pretty-text/engines/discourse-markdown/html-img.js
index e876499a252..ded425a743e 100644
--- a/app/assets/javascripts/pretty-text/engines/discourse-markdown/html-img.js
+++ b/app/assets/javascripts/pretty-text/engines/discourse-markdown/html-img.js
@@ -1,4 +1,4 @@
-// special handling for IMG tags on a line by themeselves
+// special handling for IMG tags on a line by themselves
 // we always have to handle it as so it is an inline
 // see: https://talk.commonmark.org/t/newline-and-img-tags/2511
 
diff --git a/app/assets/javascripts/pretty-text/engines/discourse-markdown/mentions.js b/app/assets/javascripts/pretty-text/engines/discourse-markdown/mentions.js
index 3c5c7d1e92b..a9a7015bc5f 100644
--- a/app/assets/javascripts/pretty-text/engines/discourse-markdown/mentions.js
+++ b/app/assets/javascripts/pretty-text/engines/discourse-markdown/mentions.js
@@ -37,7 +37,7 @@ function mentionRegex(unicodeUsernames) {
   if (unicodeUsernames) {
     try {
       // Create the regex from a string, because Babel doesn't understand
-      // Unicode property escapes and completly mangles the regexp.
+      // Unicode property escapes and completely mangles the regexp.
       const alnum = "\\p{Alphabetic}\\p{Mark}\\p{Decimal_Number}";
       return new RegExp(
         `@([${alnum}_][${alnum}._-]{0,58}[${alnum}])|@([${alnum}_])`,
diff --git a/app/assets/javascripts/pretty-text/engines/discourse-markdown/newline.js b/app/assets/javascripts/pretty-text/engines/discourse-markdown/newline.js
index 5781c9df203..e01b7bb082d 100644
--- a/app/assets/javascripts/pretty-text/engines/discourse-markdown/newline.js
+++ b/app/assets/javascripts/pretty-text/engines/discourse-markdown/newline.js
@@ -20,7 +20,7 @@ function newline(state, silent) {
   // '  \n' -> hardbreak
   // Lookup in pending chars is bad practice! Don't copy to other rules!
   // Pending string is stored in concat mode, indexed lookups will cause
-  // convertion to flat mode.
+  // conversion to flat mode.
   if (!silent) {
     if (pmax >= 0 && state.pending.charCodeAt(pmax) === 0x20) {
       if (pmax >= 1 && state.pending.charCodeAt(pmax - 1) === 0x20) {
diff --git a/app/assets/javascripts/pretty-text/engines/discourse-markdown/onebox.js b/app/assets/javascripts/pretty-text/engines/discourse-markdown/onebox.js
index 173964f17c4..ee3965f399e 100644
--- a/app/assets/javascripts/pretty-text/engines/discourse-markdown/onebox.js
+++ b/app/assets/javascripts/pretty-text/engines/discourse-markdown/onebox.js
@@ -62,7 +62,7 @@ function applyOnebox(state, silent) {
 
           let href = attrs[0][1];
 
-          // edge case ... what if this is not http or protocoless?
+          // edge case ... what if this is not http or protocolless?
           if (!/^http|^\/\//i.test(href)) {
             continue;
           }
diff --git a/app/assets/javascripts/select-kit/addon/components/composer-actions.js b/app/assets/javascripts/select-kit/addon/components/composer-actions.js
index b518602da7b..705c0002c14 100644
--- a/app/assets/javascripts/select-kit/addon/components/composer-actions.js
+++ b/app/assets/javascripts/select-kit/addon/components/composer-actions.js
@@ -225,7 +225,7 @@ export default DropdownSelectBoxComponent.extend({
       }
 
       // Edge case: If personal messages are disabled, it is possible to have
-      // no items which stil renders a button that pops up nothing. In this
+      // no items which still renders a button that pops up nothing. In this
       // case, add an option for what you're currently doing.
       if (items.length === 0) {
         showCreateTopic = true;
diff --git a/app/assets/stylesheets/common/base/magnific-popup.scss b/app/assets/stylesheets/common/base/magnific-popup.scss
index 1f89e644bfc..29896ded017 100644
--- a/app/assets/stylesheets/common/base/magnific-popup.scss
+++ b/app/assets/stylesheets/common/base/magnific-popup.scss
@@ -6,7 +6,7 @@
 //
 // 1. Default Settings
 // 2. General styles
-//    - Transluscent overlay
+//    - Translucent overlay
 //    - Containers, wrappers
 //    - Cursors
 //    - Helper classes
@@ -66,7 +66,7 @@ $use-visuallyhidden: false !default; // Hide content from browsers, but make it
 // 2. General styles
 ////////////////////////
 
-// Transluscent overlay
+// Translucent overlay
 .mfp-bg {
   top: 0;
   left: 0;
diff --git a/app/assets/stylesheets/common/d-editor.scss b/app/assets/stylesheets/common/d-editor.scss
index 68755aff33a..935e0f9169f 100644
--- a/app/assets/stylesheets/common/d-editor.scss
+++ b/app/assets/stylesheets/common/d-editor.scss
@@ -260,7 +260,7 @@
   opacity: 1;
 }
 
-// d-editor bar button sizing for all editors - this is kept seprate to keep
+// d-editor bar button sizing for all editors - this is kept separate to keep
 // everything in one place
 .d-editor-button-bar {
   margin: 0.25em;
diff --git a/app/assets/stylesheets/common/font-variables.scss b/app/assets/stylesheets/common/font-variables.scss
index 2ff960e7fca..c64ccfd2205 100644
--- a/app/assets/stylesheets/common/font-variables.scss
+++ b/app/assets/stylesheets/common/font-variables.scss
@@ -5,7 +5,7 @@
   --base-font-size-larger: 1.063em; // eq. to 17px
   --base-font-size-largest: 1.118em; // eq. to 19px
 
-  // Font-size defintions, multiplier ^ (step / interval)
+  // Font-size definitions, multiplier ^ (step / interval)
   --font-up-6: 2.296em;
   --font-up-5: 2em;
   --font-up-4: 1.7511em;
diff --git a/app/assets/stylesheets/common/foundation/variables.scss b/app/assets/stylesheets/common/foundation/variables.scss
index 3f4ce8eaf41..ff672beab27 100644
--- a/app/assets/stylesheets/common/foundation/variables.scss
+++ b/app/assets/stylesheets/common/foundation/variables.scss
@@ -50,7 +50,7 @@ $base-font-size-larger: var(--base-font-size-larger) !default;
 $base-font-size-largest: var(--base-font-size-largest) !default;
 $heading-font-family: var(--heading-font-family) !default;
 
-// Font-size defintions, multiplier ^ (step / interval)
+// Font-size definitions, multiplier ^ (step / interval)
 $font-up-6: var(--font-up-6) !default;
 $font-up-5: var(--font-up-5) !default;
 $font-up-4: var(--font-up-4) !default;
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index cf444e8709e..d75586a458f 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -326,7 +326,7 @@ class ApplicationController < ActionController::Base
   end
 
   # If a controller requires a plugin, it will raise an exception if that plugin is
-  # disabled. This allows plugins to be disabled programatically.
+  # disabled. This allows plugins to be disabled programmatically.
   def self.requires_plugin(plugin_name)
     before_action do
       raise PluginDisabled.new if Discourse.disabled_plugin_names.include?(plugin_name)
@@ -399,7 +399,7 @@ class ApplicationController < ActionController::Base
     @preloaded ||= {}
     # I dislike that there is a gsub as opposed to a gsub!
     #  but we can not be mucking with user input, I wonder if there is a way
-    #  to inject this safty deeper in the library or even in AM serializer
+    #  to inject this safety deeper in the library or even in AM serializer
     @preloaded[key] = json.gsub("</", "<\\/")
   end
 
diff --git a/app/controllers/users_email_controller.rb b/app/controllers/users_email_controller.rb
index d808c095df2..a4af506c1da 100644
--- a/app/controllers/users_email_controller.rb
+++ b/app/controllers/users_email_controller.rb
@@ -80,7 +80,7 @@ class UsersEmailController < ApplicationController
     rate_limit_second_factor!(@user)
 
     if !@error
-      # this is needed becase the form posts this field as JSON and it can be a
+      # this is needed because the form posts this field as JSON and it can be a
       # hash when authenticating security key.
       if params[:second_factor_method].to_i == UserSecondFactor.methods[:security_key]
         begin
diff --git a/app/helpers/user_notifications_helper.rb b/app/helpers/user_notifications_helper.rb
index e2f3f05906b..6d46583532d 100644
--- a/app/helpers/user_notifications_helper.rb
+++ b/app/helpers/user_notifications_helper.rb
@@ -47,7 +47,7 @@ module UserNotificationsHelper
 
     return result unless result.blank?
 
-    # If there is no first paragaph with text, return the first paragraph with
+    # If there is no first paragraph with text, return the first paragraph with
     # something else (an image) or div (a onebox).
     doc.css('body > p:not(:empty), body > div:not(:empty), body > p > div.lightbox-wrapper img').first
   end
diff --git a/app/jobs/regular/close_topic.rb b/app/jobs/regular/close_topic.rb
index fc5f84c9a92..3385d63c343 100644
--- a/app/jobs/regular/close_topic.rb
+++ b/app/jobs/regular/close_topic.rb
@@ -22,7 +22,7 @@ module Jobs
         return
       end
 
-      # this handles deleting the topic timer as wel, see TopicStatusUpdater
+      # this handles deleting the topic timer as well, see TopicStatusUpdater
       topic.update_status('autoclosed', true, user, { silent: silent })
 
       MessageBus.publish("/topic/#{topic.id}", reload_topic: true)
diff --git a/app/jobs/regular/open_topic.rb b/app/jobs/regular/open_topic.rb
index 30bddfcb08c..f1e9fe0d2ff 100644
--- a/app/jobs/regular/open_topic.rb
+++ b/app/jobs/regular/open_topic.rb
@@ -26,7 +26,7 @@ module Jobs
       else
 
         # autoclosed, false is just another way of saying open.
-        # this handles deleting the topic timer as wel, see TopicStatusUpdater
+        # this handles deleting the topic timer as well, see TopicStatusUpdater
         topic.update_status('autoclosed', false, user)
       end
 
diff --git a/app/models/concerns/has_custom_fields.rb b/app/models/concerns/has_custom_fields.rb
index ee1eedb9f1d..31b096dcee8 100644
--- a/app/models/concerns/has_custom_fields.rb
+++ b/app/models/concerns/has_custom_fields.rb
@@ -257,7 +257,7 @@ module HasCustomFields
     end
   end
 
-  # We support unique indexes on certain fields. In the event two concurrenct processes attempt to
+  # We support unique indexes on certain fields. In the event two concurrent processes attempt to
   # update the same custom field we should catch the error and perform an update instead.
   def create_singular(name, value, field_type = nil)
     write_value = value.is_a?(Hash) || field_type == :json ? value.to_json : value
diff --git a/app/models/topic_embed.rb b/app/models/topic_embed.rb
index d3ed0f1a311..69279394d26 100644
--- a/app/models/topic_embed.rb
+++ b/app/models/topic_embed.rb
@@ -240,7 +240,7 @@ class TopicEmbed < ActiveRecord::Base
     end
     return result unless result.blank?
 
-    # If there is no first paragaph, return the first div (onebox)
+    # If there is no first paragraph, return the first div (onebox)
     doc.css('div').first.to_s
   end
 
diff --git a/app/models/topic_link_click.rb b/app/models/topic_link_click.rb
index 32526189050..ab42037769e 100644
--- a/app/models/topic_link_click.rb
+++ b/app/models/topic_link_click.rb
@@ -78,7 +78,7 @@ class TopicLinkClick < ActiveRecord::Base
     # Find the forum topic link
     link = link.where(post_id: args[:post_id]) if args[:post_id].present?
 
-    # If we don't have a post, just find the first occurance of the link
+    # If we don't have a post, just find the first occurrence of the link
     link = link.where(topic_id: args[:topic_id]) if args[:topic_id].present?
     link = link.first
 
diff --git a/app/models/topic_tracking_state.rb b/app/models/topic_tracking_state.rb
index 75c2e9d9745..52dba4823d6 100644
--- a/app/models/topic_tracking_state.rb
+++ b/app/models/topic_tracking_state.rb
@@ -1,7 +1,7 @@
 # frozen_string_literal: true
 
 # this class is used to mirror unread and new status back to end users
-# in JavaScript there is a mirror class that is kept in-sync using the mssage bus
+# in JavaScript there is a mirror class that is kept in-sync using the massage bus
 # the allows end users to always know which topics have unread posts in them
 # and which topics are new
 
diff --git a/app/models/topic_user.rb b/app/models/topic_user.rb
index bcc24d979f6..f86d99ffac2 100644
--- a/app/models/topic_user.rb
+++ b/app/models/topic_user.rb
@@ -303,7 +303,7 @@ class TopicUser < ActiveRecord::Base
         threshold: SiteSetting.default_other_auto_track_topics_after_msecs
       }
 
-      # In case anyone seens "highest_seen_post_number" and gets confused, like I do.
+      # In case anyone sees "highest_seen_post_number" and gets confused, like I do.
       # highest_seen_post_number represents the highest_post_number of the topic when
       # the user visited it. It may be out of alignment with last_read, meaning
       # ... user visited the topic but did not read the posts
diff --git a/app/models/user_auth_token.rb b/app/models/user_auth_token.rb
index 48079e351d7..99dc33978ba 100644
--- a/app/models/user_auth_token.rb
+++ b/app/models/user_auth_token.rb
@@ -52,7 +52,7 @@ class UserAuthToken < ActiveRecord::Base
     return false unless User.find_by(id: user_id)&.staff?
 
     ips = UserAuthTokenLog.where(user_id: user_id).pluck(:client_ip)
-    ips.delete_at(ips.index(user_ip) || ips.length) # delete one occurance (current)
+    ips.delete_at(ips.index(user_ip) || ips.length) # delete one occurrence (current)
     ips.uniq!
     return false if ips.empty? # first login is never suspicious
 
diff --git a/app/models/user_history.rb b/app/models/user_history.rb
index 78b87c04aba..c84b326653b 100644
--- a/app/models/user_history.rb
+++ b/app/models/user_history.rb
@@ -1,7 +1,7 @@
 # frozen_string_literal: true
 
 # UserHistory stores information about actions that users have taken,
-# like deleting users, changing site settings, dimissing notifications, etc.
+# like deleting users, changing site settings, dismissing notifications, etc.
 # Use other classes, like StaffActionLogger, to log records to this table.
 class UserHistory < ActiveRecord::Base
   belongs_to :acting_user, class_name: 'User'
diff --git a/app/models/user_search.rb b/app/models/user_search.rb
index 7498b230beb..13d74df0690 100644
--- a/app/models/user_search.rb
+++ b/app/models/user_search.rb
@@ -68,7 +68,7 @@ class UserSearch
     if @term.present?
       exact_matches = scoped_users.where(username_lower: @term)
 
-      # don't polute mentions with users who haven't shown up in over a year
+      # don't pollute mentions with users who haven't shown up in over a year
       exact_matches = exact_matches.where('last_seen_at > ?', 1.year.ago) if @topic_id || @category_id
 
       exact_matches
diff --git a/app/models/user_stat.rb b/app/models/user_stat.rb
index 2921233b2a2..d2963fba8d6 100644
--- a/app/models/user_stat.rb
+++ b/app/models/user_stat.rb
@@ -161,7 +161,7 @@ class UserStat < ActiveRecord::Base
         X.c <> topics_entered
     SQL
 
-    # Update denormalzied posts_read_count
+    # Update denormalized posts_read_count
     DB.exec(<<~SQL, seen_at: last_seen)
       UPDATE user_stats SET posts_read_count = X.c
       FROM
diff --git a/app/serializers/topic_view_details_serializer.rb b/app/serializers/topic_view_details_serializer.rb
index 0a3077c9ce5..02fd53bcdfd 100644
--- a/app/serializers/topic_view_details_serializer.rb
+++ b/app/serializers/topic_view_details_serializer.rb
@@ -93,7 +93,7 @@ class TopicViewDetailsSerializer < ApplicationSerializer
 
   # NOTE: A Category Group Moderator moving a topic to a different category
   # may result in the 'can_edit?' result changing from `true` to `false`.
-  # Explictly returning a `false` value is required to update the client UI.
+  # Explicitly returning a `false` value is required to update the client UI.
   def can_edit
     scope.can_edit?(object.topic)
   end
diff --git a/app/services/search_indexer.rb b/app/services/search_indexer.rb
index d8a970f1bea..de3553daaba 100644
--- a/app/services/search_indexer.rb
+++ b/app/services/search_indexer.rb
@@ -103,7 +103,7 @@ class SearchIndexer
   end
 
   def self.update_topics_index(topic_id, title, cooked)
-    # a bit inconsitent that we use title as A and body as B when in
+    # a bit inconsistent that we use title as A and body as B when in
     # the post index body is D
     update_index(
       table: 'topic',
diff --git a/config/application.rb b/config/application.rb
index 3b382095719..5f61cbbef54 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -93,7 +93,7 @@ module Discourse
     require_dependency 'lib/highlight_js/highlight_js'
 
     # we skip it cause we configure it in the initializer
-    # the railstie for message_bus would insert it in the
+    # the railtie for message_bus would insert it in the
     # wrong position
     config.skip_message_bus_middleware = true
     config.skip_multisite_middleware = true
@@ -138,7 +138,7 @@ module Discourse
 
     config.assets.paths += %W(#{config.root}/config/locales #{config.root}/public/javascripts)
 
-    # Allows us to skip minifincation on some files
+    # Allows us to skip minification on some files
     config.assets.skip_minification = []
 
     # explicitly precompile any images in plugins ( /assets/images ) path
@@ -292,7 +292,7 @@ module Discourse
     # our setup does not use rack cache and instead defers to nginx
     config.action_dispatch.rack_cache = nil
 
-    # ember stuff only used for asset precompliation, production variant plays up
+    # ember stuff only used for asset precompilation, production variant plays up
     config.ember.variant = :development
     config.ember.ember_location = "#{Rails.root}/vendor/assets/javascripts/production/ember.js"
     config.ember.handlebars_location = "#{Rails.root}/vendor/assets/javascripts/handlebars.js"
diff --git a/config/database.yml b/config/database.yml
index be92da494de..456b8752f18 100644
--- a/config/database.yml
+++ b/config/database.yml
@@ -6,7 +6,7 @@ development:
   pool: 5
   timeout: 5000
   checkout_timeout: <%= ENV['CHECKOUT_TIMEOUT'] || 5 %>
-  advisory_locks: false # Disable until https://github.com/rails/rails/issues/40029 has beeen resolved.
+  advisory_locks: false # Disable until https://github.com/rails/rails/issues/40029 has been resolved.
   host_names:
     ### Don't include the port number here. Change the "port" site setting instead, at /admin/site_settings.
     ### If you change this setting you will need to
@@ -40,7 +40,7 @@ test:
   min_messages: warning
   pool: 5
   timeout: 5000
-  advisory_locks: false # Disable until https://github.com/rails/rails/issues/40029 has beeen resolved.
+  advisory_locks: false # Disable until https://github.com/rails/rails/issues/40029 has been resolved.
   host_names:
     - test.localhost
 
diff --git a/config/discourse_defaults.conf b/config/discourse_defaults.conf
index b7c10ed9668..fbca7c499b0 100644
--- a/config/discourse_defaults.conf
+++ b/config/discourse_defaults.conf
@@ -173,7 +173,7 @@ message_bus_redis_skip_client_commands = false
 enable_cors = false
 cors_origin = ''
 
-# enable if you really need to serve assets in prd
+# enable if you really need to serve assets in prod
 serve_static_assets = false
 
 # number of sidekiq workers (launched via unicorn master)
@@ -210,7 +210,7 @@ secret_key_base =
 fallback_assets_path =
 
 # S3 settings used for serving ALL public files
-# be sure to configre a CDN as well per cdn_url
+# be sure to configure a CDN as well per cdn_url
 s3_bucket =
 s3_region =
 s3_access_key_id =
@@ -315,7 +315,7 @@ anon_cache_store_threshold = 2
 # you may restrict it so only specific themes are approved
 # in allowlist mode all theme updates must happen via git repos
 # themes missing from the list are automatically disallowed
-# list is a comma seperated list of git repos eg:
+# list is a comma separated list of git repos eg:
 # https://github.com/discourse/discourse-custom-header-links.git,https://github.com/discourse/discourse-simple-theme.git
 allowed_theme_repos =
 
diff --git a/config/environments/test.rb b/config/environments/test.rb
index 0d753f4ed8b..502ae6b376d 100644
--- a/config/environments/test.rb
+++ b/config/environments/test.rb
@@ -12,7 +12,7 @@ Discourse::Application.configure do
   # Configure static asset server for tests with Cache-Control for performance
   config.public_file_server.enabled = true
 
-  # don't consider reqs local so we can properly handle exceptions like we do in prd
+  # don't consider reqs local so we can properly handle exceptions like we do in prod
   config.consider_all_requests_local = false
 
   # disable caching
diff --git a/config/initializers/100-watch_for_restart.rb b/config/initializers/100-watch_for_restart.rb
index bb18758cf9d..922380cf675 100644
--- a/config/initializers/100-watch_for_restart.rb
+++ b/config/initializers/100-watch_for_restart.rb
@@ -5,7 +5,7 @@
 # It simply drains all the requests (waits up to 4 seconds) and issues a HUP
 #  if you need a more sophisticated cycling restart for multiple thins it will need to be written
 #
-# This works fine for Discourse.org cause we host our app accross multiple machines, if you hosting
+# This works fine for Discourse.org cause we host our app across multiple machines, if you hosting
 #  on a single machine you have a trickier problem at hand as you need to cycle the processes in order
 #
 
diff --git a/config/nginx.sample.conf b/config/nginx.sample.conf
index 3993ff8cc9a..27863393346 100644
--- a/config/nginx.sample.conf
+++ b/config/nginx.sample.conf
@@ -9,7 +9,7 @@ upstream discourse {
 }
 
 # inactive means we keep stuff around for 1440m minutes regardless of last access (1 week)
-# levels means it is a 2 deep heirarchy cause we can have lots of files
+# levels means it is a 2 deep hierarchy cause we can have lots of files
 # max_size limits the size of the cache
 proxy_cache_path /var/nginx/cache inactive=1440m levels=1:2 keys_zone=one:10m max_size=600m;
 
@@ -131,7 +131,7 @@ server {
     }
 
     # some minimal caching here so we don't keep asking
-    # longer term we should increas probably to 1y
+    # longer term we should increase probably to 1y
     location ~ ^/javascripts/ {
       expires 1d;
       add_header Cache-Control public,immutable;
diff --git a/db/fixtures/001_refresh.rb b/db/fixtures/001_refresh.rb
index 514789616dc..3e0d603b93c 100644
--- a/db/fixtures/001_refresh.rb
+++ b/db/fixtures/001_refresh.rb
@@ -9,7 +9,7 @@ class SeedData::Refresher
     @mutex.synchronize do
       return if @refreshed
       # Fix any bust caches post initial migration
-      # Not that reset_column_information is not thread safe so we have to becareful
+      # Not that reset_column_information is not thread safe so we have to be careful
       # not to run it concurrently within the same process.
       ActiveRecord::Base.connection.tables.each do |table|
         table.classify.constantize.reset_column_information rescue nil
diff --git a/docs/SECURITY.md b/docs/SECURITY.md
index cd44bf92b4a..29225d0c3e9 100644
--- a/docs/SECURITY.md
+++ b/docs/SECURITY.md
@@ -12,7 +12,7 @@ For a list of recent security commits, check [our GitHub commits prefixed with S
 
 Discourse uses the PBKDF2 algorithm to encrypt salted passwords. This algorithm is blessed by NIST. Security experts on the web [tend to agree that PBKDF2 is a secure choice](https://security.stackexchange.com/questions/4781/do-any-security-experts-recommend-bcrypt-for-password-storage).
 
-**options you can customise in your production.rb file**
+**options you can customize in your production.rb file**
 
 - `pbkdf2_algorithm`: the hashing algorithm used (default "sha256")
 - `pbkdf2_iterations`: the number of iterations to run (default 64000)
@@ -43,7 +43,7 @@ Discourse extends the built-in Rails CSRF protection in the following ways:
 
 2. API calls using the secret API bypass CSRF checks.
 
-3. Certain pages are "cachable", we do not render the CSRF token (`<meta name='csrf-token' ...`) on any cachable pages. Instead when users are about to perform the first non GET request they retrieve the token just in time via `GET session/csrf`
+3. Certain pages are "cacheable", we do not render the CSRF token (`<meta name='csrf-token' ...`) on any cacheable pages. Instead when users are about to perform the first non GET request they retrieve the token just in time via `GET session/csrf`
 
 ### DDOS
 
diff --git a/lib/autospec/manager.rb b/lib/autospec/manager.rb
index cefce3e76a9..bd8e49803b3 100644
--- a/lib/autospec/manager.rb
+++ b/lib/autospec/manager.rb
@@ -227,7 +227,7 @@ class Autospec::Manager
         file, line = line.split(' ')
         file = reverse_symlink(file)
         file = file.sub(Rails.root.to_s + "/", "")
-        # process_change can aquire a mutex and block
+        # process_change can acquire a mutex and block
         # the acceptor
         Thread.new do
           if file =~ /(es6|js)$/
diff --git a/lib/autospec/simple_runner.rb b/lib/autospec/simple_runner.rb
index 43b112ccde7..62fcbc21a0a 100644
--- a/lib/autospec/simple_runner.rb
+++ b/lib/autospec/simple_runner.rb
@@ -23,7 +23,7 @@ module Autospec
 
       command = begin
         line_specified = specs.split.any? { |s| s =~ /\:/ } # Parallel spec can't run specific line
-        multiple_files = specs.split.count > 1 || specs == "spec" # Only paralellize multiple files
+        multiple_files = specs.split.count > 1 || specs == "spec" # Only parallelize multiple files
         if ENV["PARALLEL_SPEC"] == '1' && multiple_files && !line_specified
           "bin/turbo_rspec #{args.join(" ")} #{specs.split.join(" ")}"
         else
diff --git a/lib/badge_queries.rb b/lib/badge_queries.rb
index a8cf8a91711..e59476c3f80 100644
--- a/lib/badge_queries.rb
+++ b/lib/badge_queries.rb
@@ -93,7 +93,7 @@ module BadgeQueries
     JOIN post_actions pa1 on pa1.id = x.id
   SQL
 
-  # Incorrect, but good enough - (earlies post edited vs first edit)
+  # Incorrect, but good enough - (earliest post edited vs first edit)
   Editor = <<~SQL
     SELECT p.user_id, min(p.id) post_id, min(p.created_at) granted_at
     FROM badge_posts p
diff --git a/lib/base62.rb b/lib/base62.rb
index 70728c6a52d..e282f221a00 100644
--- a/lib/base62.rb
+++ b/lib/base62.rb
@@ -14,7 +14,7 @@ module Base62
 
     str = ""
     while num > 0
-      # prepend base62 charaters
+      # prepend base62 characters
       str = KEYS[num % BASE] + str
       num = num / BASE
     end
diff --git a/lib/discourse_tagging.rb b/lib/discourse_tagging.rb
index 4c9aa5c06ce..0699cf7e3c3 100644
--- a/lib/discourse_tagging.rb
+++ b/lib/discourse_tagging.rb
@@ -32,7 +32,7 @@ module DiscourseTagging
 
       # tag names which are visible, but not usable, by *some users*
       readonly_tags = DiscourseTagging.readonly_tag_names(guardian)
-      # tags names which are not visibile or usuable by this user
+      # tags names which are not visible or usable by this user
       hidden_tags = DiscourseTagging.hidden_tag_names(guardian)
 
       # tag names which ARE permitted by *this user*
diff --git a/lib/file_store/s3_store.rb b/lib/file_store/s3_store.rb
index 968c673af43..ab6e56bb69f 100644
--- a/lib/file_store/s3_store.rb
+++ b/lib/file_store/s3_store.rb
@@ -93,7 +93,7 @@ module FileStore
       begin
         parsed_url = URI.parse(UrlHelper.encode(url))
       rescue
-        # There are many exceptions possible here including Addressable::URI:: excpetions
+        # There are many exceptions possible here including Addressable::URI:: exceptions
         # and URI:: exceptions, catch all may seem wide, but it makes no sense to raise ever
         # on an invalid url here
         return false
diff --git a/lib/freedom_patches/active_record_attribute_methods.rb b/lib/freedom_patches/active_record_attribute_methods.rb
index 815159ff4ef..8144cba19b4 100644
--- a/lib/freedom_patches/active_record_attribute_methods.rb
+++ b/lib/freedom_patches/active_record_attribute_methods.rb
@@ -19,7 +19,7 @@ module ActiveRecord
 
       BLANK_ARRAY = [].freeze
 
-      # this patch just allows everyting in Rails 6
+      # this patch just allows everything in Rails 6
       def disallow_raw_sql!(args, permit: nil)
         # we may consider moving to https://github.com/rails/rails/pull/33330
         # once all frozen string hints are in place
diff --git a/lib/guardian/category_guardian.rb b/lib/guardian/category_guardian.rb
index 9f37b7cf99c..4e9050f29a3 100644
--- a/lib/guardian/category_guardian.rb
+++ b/lib/guardian/category_guardian.rb
@@ -1,6 +1,6 @@
 # frozen_string_literal: true
 
-#mixin for all guardian methods dealing with category permisions
+#mixin for all guardian methods dealing with category permissions
 module CategoryGuardian
 
   # Creating Method
diff --git a/lib/guardian/tag_guardian.rb b/lib/guardian/tag_guardian.rb
index e1b5a211e27..59e370cc8f9 100644
--- a/lib/guardian/tag_guardian.rb
+++ b/lib/guardian/tag_guardian.rb
@@ -1,6 +1,6 @@
 # frozen_string_literal: true
 
-#mixin for all guardian methods dealing with tagging permisions
+#mixin for all guardian methods dealing with tagging permissions
 module TagGuardian
   def can_create_tag?
     return is_admin? if SiteSetting.min_trust_to_create_tag.to_s == 'admin'
diff --git a/lib/guardian/topic_guardian.rb b/lib/guardian/topic_guardian.rb
index 81d36c02c28..8539138003c 100644
--- a/lib/guardian/topic_guardian.rb
+++ b/lib/guardian/topic_guardian.rb
@@ -1,6 +1,6 @@
 # frozen_string_literal: true
 
-#mixin for all guardian methods dealing with topic permisions
+#mixin for all guardian methods dealing with topic permissions
 module TopicGuardian
 
   def can_remove_allowed_users?(topic, target_user = nil)
diff --git a/lib/imap/sync.rb b/lib/imap/sync.rb
index 96e85ba746d..5f034270dcc 100644
--- a/lib/imap/sync.rb
+++ b/lib/imap/sync.rb
@@ -42,7 +42,7 @@ module Imap
       if @status[:uid_validity] != @group.imap_uid_validity
         # If UID validity changes, the whole mailbox must be synchronized (all
         # emails are considered new and will be associated to existent topics
-        # in Email::Reciever by matching Message-Ids).
+        # in Email::Receiver by matching Message-Ids).
         ImapSyncLog.warn("UIDVALIDITY = #{@status[:uid_validity]} does not match expected #{@group.imap_uid_validity}, invalidating IMAP cache and resyncing emails for mailbox #{@group.imap_mailbox_name}", @group)
         @group.imap_last_uid = 0
       end
diff --git a/lib/javascripts/messageformat.js b/lib/javascripts/messageformat.js
index 04f5be94a70..6626d51a168 100644
--- a/lib/javascripts/messageformat.js
+++ b/lib/javascripts/messageformat.js
@@ -10,7 +10,7 @@
 */
 (function ( root ) {
 
-  // Create the contructor function
+  // Create the constructor function
   function MessageFormat ( locale, pluralFunc ) {
     var fallbackLocale;
 
@@ -133,7 +133,7 @@
     
     var result = {
       /*
-       * Parses the input with a generated parser. If the parsing is successfull,
+       * Parses the input with a generated parser. If the parsing is successful,
        * returns a value explicitly or implicitly specified by the grammar from
        * which the parser was generated (see |PEG.buildParser|). If the parsing is
        * unsuccessful, throws |PEG.parser.SyntaxError| describing the error.
diff --git a/lib/javascripts/widget-hbs-compiler.js b/lib/javascripts/widget-hbs-compiler.js
index 58c911a1970..e36aa3549c5 100644
--- a/lib/javascripts/widget-hbs-compiler.js
+++ b/lib/javascripts/widget-hbs-compiler.js
@@ -125,7 +125,7 @@ function mustacheValue(node, state) {
       return `${useHelper(state, "iconNode")}(${valueOf(node.params[0])})`;
       break;
     default:
-      // Shortcut: If our mustach has hash arguments, we can assume it's attaching.
+      // Shortcut: If our mustache has hash arguments, we can assume it's attaching.
       // For example `{{home-logo count=123}}` can become `this.attach('home-logo, { "count": 123 });`
       let hash = node.hash;
       if (hash.pairs.length) {
diff --git a/lib/js_locale_helper.rb b/lib/js_locale_helper.rb
index fbf1fc1bdb3..c51a8812291 100644
--- a/lib/js_locale_helper.rb
+++ b/lib/js_locale_helper.rb
@@ -242,7 +242,7 @@ module JsLocaleHelper
       return locale_data if locale_data
     end
 
-    # English should alyways work
+    # English should always work
     ["en", File.join(path, "en.js")] if fallback_to_english
   end
 
diff --git a/lib/letter_avatar.rb b/lib/letter_avatar.rb
index 6c4aa1d2f9d..cdd054626a2 100644
--- a/lib/letter_avatar.rb
+++ b/lib/letter_avatar.rb
@@ -121,7 +121,7 @@ class LetterAvatar
     end
   end
 
-  # palette of optimally disctinct colors
+  # palette of optimally distinct colors
   # cf. http://tools.medialab.sciences-po.fr/iwanthue/index.php
   # parameters used:
   #   - H: 0 - 360
diff --git a/lib/middleware/enforce_hostname.rb b/lib/middleware/enforce_hostname.rb
index c462e5b7bcc..486753c7d7f 100644
--- a/lib/middleware/enforce_hostname.rb
+++ b/lib/middleware/enforce_hostname.rb
@@ -10,7 +10,7 @@ module Middleware
       # enforces hostname to match the hostname of our connection
       # this middleware lives after rails multisite so at this point
       # Discourse.current_hostname MUST be canonical, enforce it so
-      # all Rails helpers are guarenteed to use it unconditionally and
+      # all Rails helpers are guaranteed to use it unconditionally and
       # never generate incorrect links
       env[Rack::Request::HTTP_X_FORWARDED_HOST] = nil
 
diff --git a/lib/pbkdf2.rb b/lib/pbkdf2.rb
index 59317ed5cfb..62551d052f4 100644
--- a/lib/pbkdf2.rb
+++ b/lib/pbkdf2.rb
@@ -1,6 +1,6 @@
 # frozen_string_literal: true
 
-# Note: This logic was originaly extracted from the Pbkdf2 gem to fix Ruby 2.0
+# Note: This logic was originally extracted from the Pbkdf2 gem to fix Ruby 2.0
 # issues, but that gem has gone stale so we won't be returning to it.
 
 require 'openssl'
diff --git a/lib/plugin/instance.rb b/lib/plugin/instance.rb
index 784a028ce7e..6bf2fe0b53e 100644
--- a/lib/plugin/instance.rb
+++ b/lib/plugin/instance.rb
@@ -591,7 +591,7 @@ class Plugin::Instance
     end
   end
 
-  # note, we need to be able to parse seperately to activation.
+  # note, we need to be able to parse separately to activation.
   # this allows us to present information about a plugin in the UI
   # prior to activations
   def activate!
@@ -816,7 +816,7 @@ class Plugin::Instance
   end
 
   # Register a new UserApiKey scope, and its allowed routes. Scope will be prefixed
-  # with the (parametetized) plugin name followed by a colon.
+  # with the (parameterized) plugin name followed by a colon.
   #
   # For example, if discourse-awesome-plugin registered this:
   #
diff --git a/lib/post_action_creator.rb b/lib/post_action_creator.rb
index a07c0e7b7dc..559aaaf23ec 100644
--- a/lib/post_action_creator.rb
+++ b/lib/post_action_creator.rb
@@ -127,7 +127,7 @@ class PostActionCreator
 
       end
     rescue ActiveRecord::RecordNotUnique
-      # If the user already performed this action, it's proably due to a different browser tab
+      # If the user already performed this action, it's probably due to a different browser tab
       # or non-debounced clicking. We can ignore.
       result.success = true
       result.post_action = PostAction.find_by(
diff --git a/lib/post_creator.rb b/lib/post_creator.rb
index bb28f3cdd24..abc8dc445b0 100644
--- a/lib/post_creator.rb
+++ b/lib/post_creator.rb
@@ -32,7 +32,7 @@ class PostCreator
   #   skip_jobs               - Don't enqueue jobs when creation succeeds. This is needed if you
   #                             wrap `PostCreator` in a transaction, as the sidekiq jobs could
   #                             dequeue before the commit finishes. If you do this, be sure to
-  #                             call `enqueue_jobs` after the transaction is comitted.
+  #                             call `enqueue_jobs` after the transaction is committed.
   #   hidden_reason_id        - Reason for hiding the post (optional)
   #   skip_validations        - Do not validate any of the content in the post
   #   draft_key               - the key of the draft we are creating (will be deleted on success)
diff --git a/lib/post_jobs_enqueuer.rb b/lib/post_jobs_enqueuer.rb
index 1fbbe0183af..4809fdc1e86 100644
--- a/lib/post_jobs_enqueuer.rb
+++ b/lib/post_jobs_enqueuer.rb
@@ -10,7 +10,7 @@ class PostJobsEnqueuer
 
   def enqueue_jobs
     # We need to enqueue jobs after the transaction.
-    # Otherwise they might begin before the data has been comitted.
+    # Otherwise they might begin before the data has been committed.
     enqueue_post_alerts unless @opts[:import_mode]
     feature_topic_users unless @opts[:import_mode]
     trigger_post_post_process
diff --git a/lib/rate_limiter.rb b/lib/rate_limiter.rb
index bea535b7fac..12f565bf17b 100644
--- a/lib/rate_limiter.rb
+++ b/lib/rate_limiter.rb
@@ -187,7 +187,7 @@ class RateLimiter
 
     # number of events in buffer less than max allowed? OR
     (redis.llen(prefixed_key) < @max) ||
-    # age bigger than silding window size?
+    # age bigger than sliding window size?
     (age_of_oldest(now) >= @secs)
   end
 
diff --git a/lib/search.rb b/lib/search.rb
index fdc064bfd3d..4efdbff9caf 100644
--- a/lib/search.rb
+++ b/lib/search.rb
@@ -76,7 +76,7 @@ class Search
     data.force_encoding("UTF-8")
     if purpose != :topic
       # TODO cppjieba_rb is designed for chinese, we need something else for Japanese
-      # Korean appears to be safe cause words are already space seperated
+      # Korean appears to be safe cause words are already space separated
       # For Japanese we should investigate using kakasi
       if segment_cjk?
         require 'cppjieba_rb' unless defined? CppjiebaRb
diff --git a/lib/tasks/admin.rake b/lib/tasks/admin.rake
index 80c403616dc..d730ed66fe3 100644
--- a/lib/tasks/admin.rake
+++ b/lib/tasks/admin.rake
@@ -39,7 +39,7 @@ task "admin:create" => :environment do
     email = ask("Email:  ")
     existing_user = User.find_by_email(email)
 
-    # check if user account already exixts
+    # check if user account already exists
     if existing_user
       # user already exists, ask for password reset
       admin = existing_user
diff --git a/lib/tasks/autospec.rake b/lib/tasks/autospec.rake
index 895eb6da20b..0a6c9fadd5c 100644
--- a/lib/tasks/autospec.rake
+++ b/lib/tasks/autospec.rake
@@ -1,7 +1,7 @@
 # frozen_string_literal: true
 
 # I like guard, don't get me wrong, but it is just not working right
-# architectually it can not do what I want it to do, this is how I want
+# architecturally it can not do what I want it to do, this is how I want
 # it to behave
 
 desc "Run all specs automatically as needed"
diff --git a/lib/tasks/docker.rake b/lib/tasks/docker.rake
index 0e6bd415929..feafbfc2343 100644
--- a/lib/tasks/docker.rake
+++ b/lib/tasks/docker.rake
@@ -8,7 +8,7 @@
 # => SKIP_TESTS                set to 1 to skip all tests
 # => SKIP_CORE                 set to 1 to skip core tests (rspec and qunit)
 # => SKIP_PLUGINS              set to 1 to skip plugin tests (rspec and qunit)
-# => SKIP_INSTALL_PLUGINS      comma seperated list of plugins you want to skip installing
+# => SKIP_INSTALL_PLUGINS      comma separated list of plugins you want to skip installing
 # => INSTALL_OFFICIAL_PLUGINS  set to 1 to install all core plugins before running tests
 # => RUBY_ONLY                 set to 1 to skip all qunit tests
 # => JS_ONLY                   set to 1 to skip all rspec tests
diff --git a/lib/tasks/emails.rake b/lib/tasks/emails.rake
index 1ea427a21a9..2cd3e8e4fd6 100644
--- a/lib/tasks/emails.rake
+++ b/lib/tasks/emails.rake
@@ -111,7 +111,7 @@ task 'emails:test', [:email] => [:environment] do |_, args|
       STR
 
     elsif e.to_s.match(/530.*STARTTLS/)
-      # We can't run a prelimary test with STARTTLS, we'll just try sending the test email.
+      # We can't run a preliminary test with STARTTLS, we'll just try sending the test email.
       message = "OK"
 
     elsif e.to_s.match(/535/)
diff --git a/lib/tasks/uploads.rake b/lib/tasks/uploads.rake
index a085e0e1b54..42d089fcef6 100644
--- a/lib/tasks/uploads.rake
+++ b/lib/tasks/uploads.rake
@@ -46,7 +46,7 @@ def gather_uploads
         `cp --link '#{source}' '#{destination}'`
       end
 
-      # ensure file has been succesfuly copied over
+      # ensure file has been successfully copied over
       raise unless file_exists?(destination)
 
       # remap links in db
diff --git a/lib/text_cleaner.rb b/lib/text_cleaner.rb
index 179ec5f70d9..09160f3f3ef 100644
--- a/lib/text_cleaner.rb
+++ b/lib/text_cleaner.rb
@@ -4,7 +4,7 @@
 # Clean up a text
 #
 
-# Whe use ActiveSupport mb_chars from here to properly support non ascii downcase
+# We use ActiveSupport mb_chars from here to properly support non ascii downcase
 require 'active_support/core_ext/string/multibyte'
 
 class TextCleaner
diff --git a/lib/text_sentinel.rb b/lib/text_sentinel.rb
index f720e1b5032..1cd7e8d5913 100644
--- a/lib/text_sentinel.rb
+++ b/lib/text_sentinel.rb
@@ -1,6 +1,6 @@
 # frozen_string_literal: true
 
-# Whe use ActiveSupport mb_chars from here to properly support non ascii downcase
+# We use ActiveSupport mb_chars from here to properly support non ascii downcase
 # TODO remove when ruby 2.4 lands
 require 'active_support/core_ext/string/multibyte'
 
diff --git a/lib/topic_query_sql.rb b/lib/topic_query_sql.rb
index 93a2b9a8625..c96f46c68c6 100644
--- a/lib/topic_query_sql.rb
+++ b/lib/topic_query_sql.rb
@@ -14,7 +14,7 @@ module TopicQuerySQL
       -"CASE WHEN categories.id = #{SiteSetting.uncategorized_category_id.to_i} THEN '' ELSE categories.name END #{dir}"
     end
 
-    # If you've clearned the pin, use bumped_at, otherwise put it at the top
+    # If you've cleared the pin, use bumped_at, otherwise put it at the top
     def order_with_pinned_sql
       -"CASE
         WHEN (COALESCE(topics.pinned_at, '#{lowest_date}') > COALESCE(tu.cleared_pinned_at, '#{lowest_date}'))
@@ -23,7 +23,7 @@ module TopicQuerySQL
        END DESC"
     end
 
-    # If you've clearned the pin, use bumped_at, otherwise put it at the top
+    # If you've cleared the pin, use bumped_at, otherwise put it at the top
     def order_nocategory_with_pinned_sql
       -"CASE
         WHEN topics.pinned_globally
diff --git a/lib/url_helper.rb b/lib/url_helper.rb
index be75c5d0a29..4bbafe331f3 100644
--- a/lib/url_helper.rb
+++ b/lib/url_helper.rb
@@ -87,7 +87,7 @@ class UrlHelper
     # to avoid asset_host mixups
     return schemaless(url) if secure
 
-    # PERF: avoid parsing url excpet for extreme conditions
+    # PERF: avoid parsing url except for extreme conditions
     # this is a hot path used on home page
     filename = url
     if url.include?("?")
diff --git a/plugins/discourse-local-dates/assets/javascripts/lib/date-with-zone-helper.js.es6 b/plugins/discourse-local-dates/assets/javascripts/lib/date-with-zone-helper.js.es6
index d82cfa4d0d4..0f4abe2cd53 100644
--- a/plugins/discourse-local-dates/assets/javascripts/lib/date-with-zone-helper.js.es6
+++ b/plugins/discourse-local-dates/assets/javascripts/lib/date-with-zone-helper.js.es6
@@ -6,11 +6,11 @@ const { getProperties } = Ember;
 
   - add(count unit) adds a COUNT of UNITS to a date
   - subtract(count unit) subtracts a COUNT of UNITS to a date
-  - format(format) formats a date with zone in a consitent way, optional moment format
+  - format(format) formats a date with zone in a consistent way, optional moment format
   - isDST() allows to know if a date in a specified timezone is currently under DST
   - datetimeWithZone(timezone) returns a new moment object with timezone applied
   - datetime returns the moment object
-  - unitRepetitionsBetweenDates(duration, date) return the number of repertitions of
+  - unitRepetitionsBetweenDates(duration, date) return the number of repetitions of
   duration between two dates, eg for duration: "1.weeks", "2.months"...
 */
 export default class DateWithZoneHelper {
diff --git a/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/new_user_narrative_spec.rb b/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/new_user_narrative_spec.rb
index 35b9c1e4b31..e249d98a441 100644
--- a/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/new_user_narrative_spec.rb
+++ b/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/new_user_narrative_spec.rb
@@ -637,7 +637,7 @@ describe DiscourseNarrativeBot::NewUserNarrative do
       end
     end
 
-    describe 'fomatting tutorial' do
+    describe 'formatting tutorial' do
       before do
         narrative.set_data(user, state: :tutorial_formatting, topic_id: topic.id)
       end
diff --git a/plugins/discourse-presence/spec/requests/presence_controller_spec.rb b/plugins/discourse-presence/spec/requests/presence_controller_spec.rb
index 8df3086aef8..9f374dbd404 100644
--- a/plugins/discourse-presence/spec/requests/presence_controller_spec.rb
+++ b/plugins/discourse-presence/spec/requests/presence_controller_spec.rb
@@ -406,7 +406,7 @@ describe ::Presence::PresencesController do
         )
       end
 
-      it 'publises the right message when closing composer in public topic' do
+      it 'publishes the right message when closing composer in public topic' do
         messages = MessageBus.track_publish do
           post '/presence/publish.json', params: {
             topic_id: public_topic.id,
@@ -424,7 +424,7 @@ describe ::Presence::PresencesController do
         expect(message.user_ids).to eq(nil)
       end
 
-      it 'publises the right message when closing composer in private topic' do
+      it 'publishes the right message when closing composer in private topic' do
         messages = MessageBus.track_publish do
           post '/presence/publish.json', params: {
             topic_id: private_topic.id,
@@ -442,7 +442,7 @@ describe ::Presence::PresencesController do
         expect(message.user_ids).to eq(nil)
       end
 
-      it 'publises the right message when closing composer in private message' do
+      it 'publishes the right message when closing composer in private message' do
         post = Fabricate(:post, topic: private_message, user: user)
 
         messages = MessageBus.track_publish do
diff --git a/plugins/poll/assets/javascripts/lib/discourse-markdown/poll.js.es6 b/plugins/poll/assets/javascripts/lib/discourse-markdown/poll.js.es6
index e004aefa759..061ccceaf97 100644
--- a/plugins/poll/assets/javascripts/lib/discourse-markdown/poll.js.es6
+++ b/plugins/poll/assets/javascripts/lib/discourse-markdown/poll.js.es6
@@ -292,7 +292,7 @@ export function setup(helper) {
 
 /*!
  * Joseph Myer's md5() algorithm wrapped in a self-invoked function to prevent
- * global namespace polution, modified to hash unicode characters as UTF-8.
+ * global namespace pollution, modified to hash unicode characters as UTF-8.
  *
  * Copyright 1999-2010, Joseph Myers, Paul Johnston, Greg Holt, Will Bond <will@wbond.net>
  * http://www.myersdaily.org/joseph/javascript/md5-text.html
diff --git a/plugins/poll/spec/controllers/posts_controller_spec.rb b/plugins/poll/spec/controllers/posts_controller_spec.rb
index 805641a1882..37bcb45e75c 100644
--- a/plugins/poll/spec/controllers/posts_controller_spec.rb
+++ b/plugins/poll/spec/controllers/posts_controller_spec.rb
@@ -127,7 +127,7 @@ describe PostsController do
       expect(Poll.find_by(post_id: json["id"]).name).to eq("&lt;script&gt;alert(&#39;xss&#39;)&lt;/script&gt;")
     end
 
-    it "also works whe there is a link starting with '[poll'" do
+    it "also works when there is a link starting with '[poll'" do
       post :create, params: {
         title: title, raw: "[Polls are awesome](/foobar)\n[poll]\n- A\n- B\n[/poll]"
       }, format: :json
@@ -138,7 +138,7 @@ describe PostsController do
       expect(Poll.exists?(post_id: json["id"])).to eq(true)
     end
 
-    it "prevents pollception" do
+    it "prevents poll-inception" do
       post :create, params: {
         title: title, raw: "[poll name=1]\n- A\n[poll name=2]\n- B\n- C\n[/poll]\n- D\n[/poll]"
       }, format: :json
diff --git a/plugins/poll/spec/models/poll_spec.rb b/plugins/poll/spec/models/poll_spec.rb
index fed3310b84a..1b1f8e8c7f5 100644
--- a/plugins/poll/spec/models/poll_spec.rb
+++ b/plugins/poll/spec/models/poll_spec.rb
@@ -56,7 +56,7 @@ describe ::DiscoursePoll::Poll do
       expect(poll.can_see_results?(user)).to eq(true)
     end
 
-    it "only staff memebers can see results when results setting is staff_only" do
+    it "only staff members can see results when results setting is staff_only" do
       post = Fabricate(:post, raw: "[poll results=staff_only]\n- A\n- B\n[/poll]")
       user = Fabricate(:user)
       poll = post.polls.first
diff --git a/plugins/styleguide/assets/javascripts/discourse/templates/styleguide/atoms/02-buttons.hbs b/plugins/styleguide/assets/javascripts/discourse/templates/styleguide/atoms/02-buttons.hbs
index 9ffac0bd10c..c9dcb818cc4 100644
--- a/plugins/styleguide/assets/javascripts/discourse/templates/styleguide/atoms/02-buttons.hbs
+++ b/plugins/styleguide/assets/javascripts/discourse/templates/styleguide/atoms/02-buttons.hbs
@@ -80,12 +80,12 @@
 
 {{#styleguide-example title=".btn-flat - sizes"}}
   {{#each dummy.buttonSizes as |bs|}}
-    {{flat-button icon="trash-alt" disabled=bs.disabled transaltedTitle=bs.title}}
+    {{flat-button icon="trash-alt" disabled=bs.disabled translatedTitle=bs.title}}
   {{/each}}
 {{/styleguide-example}}
 
 {{#styleguide-example title=".btn-flat - states"}}
   {{#each dummy.buttonStates as |bs|}}
-    {{flat-button icon="trash-alt" disabled=bs.disabled transaltedTitle=bs.title}}
+    {{flat-button icon="trash-alt" disabled=bs.disabled translatedTitle=bs.title}}
   {{/each}}
 {{/styleguide-example}}
diff --git a/script/benchmarks/markdown/most_features.md b/script/benchmarks/markdown/most_features.md
index 9f2924a6ec0..5d037ecc0e6 100644
--- a/script/benchmarks/markdown/most_features.md
+++ b/script/benchmarks/markdown/most_features.md
@@ -150,7 +150,7 @@ The killer feature of `markdown-it` is very effective support of
 [syntax plugins](https://www.npmjs.org/browse/keyword/markdown-it-plugin).
 
 
-### [Emojies](https://github.com/markdown-it/markdown-it-emoji)
+### [Emojis](https://github.com/markdown-it/markdown-it-emoji)
 
 > Classic markup: :wink:  :cry: :laughing: :yum: :surfing_woman:t4:   
 >
diff --git a/script/discourse b/script/discourse
index fce25d81279..32b0bb30221 100755
--- a/script/discourse
+++ b/script/discourse
@@ -4,7 +4,7 @@
 require "thor"
 
 class DiscourseCLI < Thor
-  desc "remap [--global,--regex] FROM TO", "Remap a string sequence accross all tables"
+  desc "remap [--global,--regex] FROM TO", "Remap a string sequence across all tables"
   long_desc <<-LONGDESC
     Replace a string sequence FROM with TO across all tables.
 
diff --git a/script/import_scripts/answerhub.rb b/script/import_scripts/answerhub.rb
index 56670725b8f..035d625c293 100644
--- a/script/import_scripts/answerhub.rb
+++ b/script/import_scripts/answerhub.rb
@@ -3,7 +3,7 @@
 # AnswerHub Importer
 #
 # Based on having access to a mysql dump.
-# Pass in the ENV variables listed below before runing the script.
+# Pass in the ENV variables listed below before running the script.
 
 require_relative 'base'
 require 'mysql2'
diff --git a/script/import_scripts/askbot.rb b/script/import_scripts/askbot.rb
index 422c8fa3118..7bc7866a0ef 100644
--- a/script/import_scripts/askbot.rb
+++ b/script/import_scripts/askbot.rb
@@ -16,7 +16,7 @@ class ImportScripts::MyAskBot < ImportScripts::Base
   DB_PASS    = 'yeah, right'
 
   # A list of categories to create. Any post with one of these tags will be
-  # assigned to that category. Ties are broken by list orer.
+  # assigned to that category. Ties are broken by list order.
   CATEGORIES = [ 'Nonconvex', 'TFOCS', 'MIDCP', 'FAQ' ]
 
   def initialize
diff --git a/script/import_scripts/discuz_x.rb b/script/import_scripts/discuz_x.rb
index 7b4679981f8..edced0e7ab3 100644
--- a/script/import_scripts/discuz_x.rb
+++ b/script/import_scripts/discuz_x.rb
@@ -158,7 +158,7 @@ class ImportScripts::DiscuzX < ImportScripts::Base
 
       break if results.size < 1
 
-      # TODO: breaks the scipt reported by some users
+      # TODO: breaks the script reported by some users
       # next if all_records_exist? :users, users.map {|u| u["id"].to_i}
 
       create_users(results, total: total_count, offset: offset) do |user|
diff --git a/script/import_scripts/mbox/settings.yml b/script/import_scripts/mbox/settings.yml
index 60322ec3058..4c0a3acc11a 100644
--- a/script/import_scripts/mbox/settings.yml
+++ b/script/import_scripts/mbox/settings.yml
@@ -43,7 +43,7 @@ tags:
 #  announcement: ["ann", "announce", "announcement"]
 #  "": ["foo", "bar"]
 
-# These prefixes will be removed from the beginning of topic titles. You can use regular expessions.
+# These prefixes will be removed from the beginning of topic titles. You can use regular expressions.
 # Prefixes are case-insensitive. You can add additional prefixes (e.g. localized prefixes from
 # https://en.wikipedia.org/wiki/List_of_email_subject_abbreviations#Abbreviations_in_other_languages).
 remove_subject_prefixes:
diff --git a/script/import_scripts/quandora/test/test_quandora_api.rb b/script/import_scripts/quandora/test/test_quandora_api.rb
index b7101053c2a..784ba4fb855 100644
--- a/script/import_scripts/quandora/test/test_quandora_api.rb
+++ b/script/import_scripts/quandora/test/test_quandora_api.rb
@@ -23,7 +23,7 @@ class TestQuandoraApi < Minitest::Test
     @quandora = QuandoraApi.new @domain, @username, @password
   end
 
-  def test_intialize
+  def test_initialize
     assert_equal @domain, @quandora.domain
     assert_equal @username, @quandora.username
     assert_equal @password, @quandora.password
diff --git a/script/import_scripts/socialcast/test/test_data.rb b/script/import_scripts/socialcast/test/test_data.rb
index 3b0dc6e2adc..5bdbf52cc9f 100644
--- a/script/import_scripts/socialcast/test/test_data.rb
+++ b/script/import_scripts/socialcast/test/test_data.rb
@@ -435,7 +435,7 @@ USERS = '{
             "custom_fields": [
                 {
                     "id": "resume",
-                    "value": "I currently assist the VP of Marketing in making sure that all marketing related activites are rolled out properly in the Americas market.",
+                    "value": "I currently assist the VP of Marketing in making sure that all marketing related activities are rolled out properly in the Americas market.",
                     "label": "Job Description"
                 },
                 {
@@ -2531,12 +2531,12 @@ MESSAGES = '{
                         {
                             "id": 108,
                             "url": "https://demo.socialcast.com/attachments/108",
-                            "filename": "108-reverse-a-algorithm-refernece-V7.pdf",
-                            "public_filename": "https://socialcast-demo.s3.amazonaws.com/tenants/5/attachments/108/108-reverse-a-algorithm-refernece-V7.pdf?AWSAccessKeyId=AKIAIV34WIEKJKCLRBBQ&Expires=1465128000&Signature=JP4%2BXB76kk%2BhCcuJQpZDSDx3NU4%3D",
+                            "filename": "108-reverse-a-algorithm-reference-V7.pdf",
+                            "public_filename": "https://socialcast-demo.s3.amazonaws.com/tenants/5/attachments/108/108-reverse-a-algorithm-reference-V7.pdf?AWSAccessKeyId=AKIAIV34WIEKJKCLRBBQ&Expires=1465128000&Signature=JP4%2BXB76kk%2BhCcuJQpZDSDx3NU4%3D",
                             "external_host_type": null,
                             "file_extension": "pdf",
                             "content_type": "application/pdf",
-                            "html_filename": "108-reverse-a-algorithm-refernece-V7.pdf"
+                            "html_filename": "108-reverse-a-algorithm-reference-V7.pdf"
                         }
                     ],
                     "media_files": [],
@@ -8166,8 +8166,8 @@ MESSAGES_PG_2 = '{
                         "back_in_office_on": null,
                         "company_login": null
                     },
-                    "text": "After speaking with a number of our younger employees I think tutition reimbursement is really key to retaining them. Many of them are looking to earn advanced degrees. If we can setup a plan that accomplishes this effectively we can really grow our staff\'s ability and knowledge.",
-                    "html_body": "<div class=\"markdown-body\"><p>After speaking with a number of our younger employees I think tutition reimbursement is really key to retaining them. Many of them are looking to earn advanced degrees. If we can setup a plan that accomplishes this effectively we can really grow our staff\'s ability and knowledge.</p></div>",
+                    "text": "After speaking with a number of our younger employees I think tuition reimbursement is really key to retaining them. Many of them are looking to earn advanced degrees. If we can setup a plan that accomplishes this effectively we can really grow our staff\'s ability and knowledge.",
+                    "html_body": "<div class=\"markdown-body\"><p>After speaking with a number of our younger employees I think tuition reimbursement is really key to retaining them. Many of them are looking to earn advanced degrees. If we can setup a plan that accomplishes this effectively we can really grow our staff\'s ability and knowledge.</p></div>",
                     "created_at": "2016-05-21T20:48:41+00:00",
                     "updated_at": "2016-05-21T20:48:41+00:00",
                     "attachments": [],
diff --git a/script/import_scripts/socialcast/test/test_socialcast_api.rb b/script/import_scripts/socialcast/test/test_socialcast_api.rb
index 9f5430f1068..70ad038c8b4 100644
--- a/script/import_scripts/socialcast/test/test_socialcast_api.rb
+++ b/script/import_scripts/socialcast/test/test_socialcast_api.rb
@@ -23,7 +23,7 @@ class TestSocialcastApi < Minitest::Test
     @socialcast = SocialcastApi.new @domain, @username, @password
   end
 
-  def test_intialize
+  def test_initialize
     assert_equal @domain, @socialcast.domain
     assert_equal @username, @socialcast.username
     assert_equal @password, @socialcast.password
diff --git a/spec/components/admin_user_index_query_spec.rb b/spec/components/admin_user_index_query_spec.rb
index e41c7fc068a..fb06da9f301 100644
--- a/spec/components/admin_user_index_query_spec.rb
+++ b/spec/components/admin_user_index_query_spec.rb
@@ -33,7 +33,7 @@ describe AdminUserIndexQuery do
       expect(query.find_users_query.to_sql).to match("trust_level ASC")
     end
 
-    it "allows custom ordering for stats wtih default direction" do
+    it "allows custom ordering for stats with default direction" do
       query = ::AdminUserIndexQuery.new(order: "topics_viewed")
       expect(query.find_users_query.to_sql).to match("topics_entered DESC")
     end
diff --git a/spec/components/auth/github_authenticator_spec.rb b/spec/components/auth/github_authenticator_spec.rb
index 2a3a83cf298..ee6917bfe3b 100644
--- a/spec/components/auth/github_authenticator_spec.rb
+++ b/spec/components/auth/github_authenticator_spec.rb
@@ -38,7 +38,7 @@ describe Auth::GithubAuthenticator do
       expect(result.email).to eq(user.email)
       expect(result.email_valid).to eq(true)
 
-      # Authenticates again when user has Github user info
+      # Authenticates again when user has GitHub user info
       result = authenticator.after_authenticate(data)
 
       expect(result.email).to eq(user.email)
diff --git a/spec/components/concern/has_custom_fields_spec.rb b/spec/components/concern/has_custom_fields_spec.rb
index 51138c843f6..6fab074a08d 100644
--- a/spec/components/concern/has_custom_fields_spec.rb
+++ b/spec/components/concern/has_custom_fields_spec.rb
@@ -146,7 +146,7 @@ describe HasCustomFields do
       expect(db_item.custom_fields).to eq("a" => ["b", "10", "d"])
     end
 
-    it "supportes type coersion" do
+    it "supports type coercion" do
       test_item = CustomFieldsTestItem.new
       CustomFieldsTestItem.register_custom_field_type("bool", :boolean)
       CustomFieldsTestItem.register_custom_field_type("int", :integer)
diff --git a/spec/components/concern/second_factor_manager_spec.rb b/spec/components/concern/second_factor_manager_spec.rb
index 865b1113bb4..1dd7bb47286 100644
--- a/spec/components/concern/second_factor_manager_spec.rb
+++ b/spec/components/concern/second_factor_manager_spec.rb
@@ -129,20 +129,20 @@ RSpec.describe SecondFactorManager do
 
   describe "#has_multiple_second_factor_methods?" do
     context "when security keys and totp are enabled" do
-      it "retrns true" do
+      it "returns true" do
         expect(user.has_multiple_second_factor_methods?).to eq(true)
       end
     end
 
     context "if the totp gets disabled" do
-      it "retrns false" do
+      it "returns false" do
         disable_totp
         expect(user.has_multiple_second_factor_methods?).to eq(false)
       end
     end
 
     context "if the security key gets disabled" do
-      it "retrns false" do
+      it "returns false" do
         disable_security_key
         expect(user.has_multiple_second_factor_methods?).to eq(false)
       end
diff --git a/spec/components/discourse_event_spec.rb b/spec/components/discourse_event_spec.rb
index 38a6de6d64b..4e87a079155 100644
--- a/spec/components/discourse_event_spec.rb
+++ b/spec/components/discourse_event_spec.rb
@@ -67,7 +67,7 @@ describe DiscourseEvent do
     context 'when multiple events exist' do
 
       let(:event_handler_2) do
-        Proc.new { |user| user.job = 'Supervillian' }
+        Proc.new { |user| user.job = 'Supervillain' }
       end
 
       before do
@@ -80,7 +80,7 @@ describe DiscourseEvent do
       end
 
       it 'triggers both events' do
-        expect(harvey.job).to eq('Supervillian')
+        expect(harvey.job).to eq('Supervillain')
         expect(harvey.name).to eq('Two Face')
       end
 
diff --git a/spec/components/email/receiver_spec.rb b/spec/components/email/receiver_spec.rb
index fcdc094058c..dec90fd99b8 100644
--- a/spec/components/email/receiver_spec.rb
+++ b/spec/components/email/receiver_spec.rb
@@ -414,7 +414,7 @@ describe Email::Receiver do
 
     it "handles multiple paragraphs" do
       expect { process(:paragraphs) }.to change { topic.posts.count }
-      expect(topic.posts.last.raw).to eq("Do you like liquorice?\n\nI really like them. One could even say that I am *addicted* to liquorice. Anf if\nyou can mix it up with some anise, then I'm in heaven ;)")
+      expect(topic.posts.last.raw).to eq("Do you like liquorice?\n\nI really like them. One could even say that I am *addicted* to liquorice. And if\nyou can mix it up with some anise, then I'm in heaven ;)")
     end
 
     it "handles invalid from header" do
@@ -1167,7 +1167,7 @@ describe Email::Receiver do
       SiteSetting.alternative_reply_by_email_addresses = nil
     end
 
-    it "it maches nothing if there is not reply_by_email_address" do
+    it "it matches nothing if there is not reply_by_email_address" do
       expect(Email::Receiver.reply_by_email_address_regex).to eq(/$a/)
     end
 
@@ -1366,7 +1366,7 @@ describe Email::Receiver do
           SiteSetting.forwarded_emails_behaviour = "create_replies"
         end
 
-        context "when a reply contains a forwareded email" do
+        context "when a reply contains a forwarded email" do
           include_examples "does not create staged users", :reply_and_forwarded
         end
 
diff --git a/spec/components/email/styles_spec.rb b/spec/components/email/styles_spec.rb
index 1520662dc50..d5767310e12 100644
--- a/spec/components/email/styles_spec.rb
+++ b/spec/components/email/styles_spec.rb
@@ -326,7 +326,7 @@ describe Email::Styles do
         strip_and_inline
         expect(@frag.to_s).to include("cid:email/test.png")
         expect(@frag.to_s).to include("cid:email/test2.ico")
-        expect(@frag.css('[data-sripped-secure-media]')).not_to be_present
+        expect(@frag.css('[data-stripped-secure-media]')).not_to be_present
         expect(@frag.css('[data-embedded-secure-image]')[0].attr('style')).to eq('width: 16px; height: 16px;')
         expect(@frag.css('[data-embedded-secure-image]')[1].attr('style')).to eq('width: 60px; max-height: 80%; max-width: 20%; height: auto; float: left; margin-right: 10px;')
       end
@@ -358,7 +358,7 @@ describe Email::Styles do
           strip_and_inline
           expect(@frag.to_s).to include("cid:email/test.png")
           expect(@frag.to_s).to include("cid:email/test2.ico")
-          expect(@frag.css('[data-sripped-secure-media]')).not_to be_present
+          expect(@frag.css('[data-stripped-secure-media]')).not_to be_present
           expect(@frag.css('[data-embedded-secure-image]')[1].attr('style')).to eq('width: 60px; max-height: 80%; max-width: 20%; height: auto; float: left; margin-right: 10px;')
         end
       end
@@ -410,7 +410,7 @@ describe Email::Styles do
         it "keeps the special onebox styles" do
           strip_and_inline
           expect(@frag.to_s).to include("cid:email/test.png")
-          expect(@frag.css('[data-sripped-secure-media]')).not_to be_present
+          expect(@frag.css('[data-stripped-secure-media]')).not_to be_present
           expect(@frag.css('[data-embedded-secure-image]')[0].attr('style')).to eq('width: 20px; height: 20px; float: none; vertical-align: middle; max-height: 80%; max-width: 20%; height: auto; float: left; margin-right: 10px;')
         end
       end
diff --git a/spec/components/email_cook_spec.rb b/spec/components/email_cook_spec.rb
index b2fdc478018..d47f5b91f80 100644
--- a/spec/components/email_cook_spec.rb
+++ b/spec/components/email_cook_spec.rb
@@ -91,16 +91,16 @@ describe EmailCook do
     long = plaintext(<<~LONG_EMAIL)
       Lorem ipsum dolor sit amet, consectetur adipiscing elit.
 
-          this is indended by 4 spaces
-       this is indended by 1 space
+          this is intended by 4 spaces
+       this is intended by 1 space
       no indentation, but lots       of spaces
     LONG_EMAIL
 
     long_cooked = (+<<~LONG_COOKED).strip!
       Lorem ipsum dolor sit amet, consectetur adipiscing elit.
       <br>
-      <br>#{nbsp}#{nbsp}#{nbsp}#{nbsp}this is indended by 4 spaces
-      <br> this is indended by 1 space
+      <br>#{nbsp}#{nbsp}#{nbsp}#{nbsp}this is intended by 4 spaces
+      <br> this is intended by 1 space
       <br>no indentation, but lots       of spaces
       <br>
     LONG_COOKED
diff --git a/spec/components/file_store/s3_store_spec.rb b/spec/components/file_store/s3_store_spec.rb
index 8b6831219bc..3b617cf523f 100644
--- a/spec/components/file_store/s3_store_spec.rb
+++ b/spec/components/file_store/s3_store_spec.rb
@@ -16,7 +16,7 @@ describe FileStore::S3Store do
   let(:optimized_image_file) { file_from_fixtures("logo.png") }
   let(:uploaded_file) { file_from_fixtures("logo.png") }
   fab!(:upload) do
-    Fabricate(:upload, sha1: Digest::SHA1.hexdigest('secreet image string'))
+    Fabricate(:upload, sha1: Digest::SHA1.hexdigest('secret image string'))
   end
 
   before do
diff --git a/spec/components/guardian/user_guardian_spec.rb b/spec/components/guardian/user_guardian_spec.rb
index ef87af6399d..70c9ec1ba2f 100644
--- a/spec/components/guardian/user_guardian_spec.rb
+++ b/spec/components/guardian/user_guardian_spec.rb
@@ -273,7 +273,7 @@ describe UserGuardian do
         expect(guardian.can_delete_user?(user)).to eq(true)
       end
 
-      it "is allowed when user created multiple posts in PMs to themself" do
+      it "is allowed when user created multiple posts in PMs to themselves" do
         topic = Fabricate(:private_message_topic, user: user, topic_allowed_users: [
           Fabricate.build(:topic_allowed_user, user: user)
         ])
diff --git a/spec/components/guardian_spec.rb b/spec/components/guardian_spec.rb
index 38478cea97d..aa686bab3b0 100644
--- a/spec/components/guardian_spec.rb
+++ b/spec/components/guardian_spec.rb
@@ -664,7 +664,7 @@ describe Guardian do
         end
       end
 
-      context "when PM has receached the maximum number of recipients" do
+      context "when PM has reached the maximum number of recipients" do
         before do
           SiteSetting.max_allowed_message_recipients = 2
         end
@@ -706,7 +706,7 @@ describe Guardian do
       expect(Guardian.new(admin).can_invite_via_email?(topic)).to be_falsey
     end
 
-    it 'returns correct valuse when user approval is required' do
+    it 'returns correct values when user approval is required' do
       SiteSetting.must_approve_users = true
 
       expect(Guardian.new(trust_level_2).can_invite_via_email?(topic)).to be_falsey
diff --git a/spec/components/html_to_markdown_spec.rb b/spec/components/html_to_markdown_spec.rb
index b5db6e716cc..ea24eb8e66a 100644
--- a/spec/components/html_to_markdown_spec.rb
+++ b/spec/components/html_to_markdown_spec.rb
@@ -149,7 +149,7 @@ describe HtmlToMarkdown do
     expect(html_to_markdown(%Q{<img src="foo.bar">})).to eq("")
   end
 
-  it "keeps <img> with src='cid:' whith 'keep_cid_imgs'" do
+  it "keeps <img> with src='cid:' with 'keep_cid_imgs'" do
     expect(html_to_markdown(HTML_WITH_CID_IMG, keep_cid_imgs: true)).to eq(HTML_WITH_CID_IMG)
   end
 
@@ -391,7 +391,7 @@ describe HtmlToMarkdown do
 
   end
 
-  it "supoorts <table>" do
+  it "supports <table>" do
     html = <<~HTML
       <table>
         <thead>
diff --git a/spec/components/image_sizer_spec.rb b/spec/components/image_sizer_spec.rb
index 7ffe352a4c2..5c41afec225 100644
--- a/spec/components/image_sizer_spec.rb
+++ b/spec/components/image_sizer_spec.rb
@@ -32,7 +32,7 @@ describe ImageSizer do
       @w, @h = ImageSizer.resize(600, 123)
     end
 
-    it 'returns the maxmimum width if larger than the maximum' do
+    it 'returns the maximum width if larger than the maximum' do
       expect(@w).to eq(500)
     end
 
@@ -48,7 +48,7 @@ describe ImageSizer do
       @w, @h = ImageSizer.resize(123, 600)
     end
 
-    it 'returns the maxmimum height if larger than the maximum' do
+    it 'returns the maximum height if larger than the maximum' do
       expect(@h).to eq(500)
     end
 
diff --git a/spec/components/imap/imap_helper.rb b/spec/components/imap/imap_helper.rb
index 1248fa0cae7..6407a54b980 100644
--- a/spec/components/imap/imap_helper.rb
+++ b/spec/components/imap/imap_helper.rb
@@ -19,7 +19,7 @@ def EmailFabricator(options)
   email += "In-Reply-To: #{options[:in_reply_to]}\n" if options[:in_reply_to]
   email += "References: #{options[:in_reply_to]}\n" if options[:in_reply_to]
   email += "Message-ID: <#{options[:message_id]}>\n" if options[:message_id]
-  email += "Subject: #{options[:subject] || "This is a test email subhect"}\n"
+  email += "Subject: #{options[:subject] || "This is a test email subject"}\n"
   email += "Mime-Version: 1.0\n"
   email += "Content-Type: #{options[:content_type] || "text/plain;\n charset=UTF-8"}\n"
   email += "Content-Transfer-Encoding: 7bit\n"
diff --git a/spec/components/imap/sync_spec.rb b/spec/components/imap/sync_spec.rb
index da0ed74d250..7eac7ac6a33 100644
--- a/spec/components/imap/sync_spec.rb
+++ b/spec/components/imap/sync_spec.rb
@@ -530,7 +530,7 @@ describe Imap::Sync do
 
   end
 
-  context 'invaidated previous sync' do
+  context 'invalidated previous sync' do
     let(:subject) { 'Testing email post' }
 
     let(:first_from) { 'john@free.fr' }
diff --git a/spec/components/inline_oneboxer_spec.rb b/spec/components/inline_oneboxer_spec.rb
index 761e1c00d8f..6a5917af313 100644
--- a/spec/components/inline_oneboxer_spec.rb
+++ b/spec/components/inline_oneboxer_spec.rb
@@ -116,7 +116,7 @@ describe InlineOneboxer do
       expect(onebox[:title]).to eq("Hello 🍕 with an emoji")
     end
 
-    it "will append the post number post auther's username to the title" do
+    it "will append the post number post author's username to the title" do
       topic = Fabricate(:topic, title: "Inline oneboxer")
       Fabricate(:post, topic: topic) # OP
       Fabricate(:post, topic: topic)
diff --git a/spec/components/json_error_spec.rb b/spec/components/json_error_spec.rb
index 3b064a6381d..fdeaa6ce83d 100644
--- a/spec/components/json_error_spec.rb
+++ b/spec/components/json_error_spec.rb
@@ -42,7 +42,7 @@ describe JsonError do
     end
   end
 
-  describe "an activerecord objec with errors" do
+  describe "an activerecord object with errors" do
     let(:invalid_user) { User.new }
     it "returns the errors correctly" do
       expect(invalid_user).not_to be_valid
diff --git a/spec/components/middleware/anonymous_cache_spec.rb b/spec/components/middleware/anonymous_cache_spec.rb
index 33089a25278..c9ad5b558ad 100644
--- a/spec/components/middleware/anonymous_cache_spec.rb
+++ b/spec/components/middleware/anonymous_cache_spec.rb
@@ -14,7 +14,7 @@ describe Middleware::AnonymousCache do
       Middleware::AnonymousCache::Helper.new(env(opts))
     end
 
-    context "cachable?" do
+    context "cacheable?" do
       it "true by default" do
         expect(new_helper.cacheable?).to eq(true)
       end
diff --git a/spec/components/new_post_manager_spec.rb b/spec/components/new_post_manager_spec.rb
index c7aa2415093..29ac3ca83b8 100644
--- a/spec/components/new_post_manager_spec.rb
+++ b/spec/components/new_post_manager_spec.rb
@@ -713,7 +713,7 @@ describe NewPostManager do
   end
 
   context "private message via email" do
-    it "doesn't enqueue authentiation results failure" do
+    it "doesn't enqueue authentication results failure" do
       manager = NewPostManager.new(
         topic.user,
         raw: 'this is emailed content',
diff --git a/spec/components/onpdiff_spec.rb b/spec/components/onpdiff_spec.rb
index f59bd80cb0e..56cacf75c13 100644
--- a/spec/components/onpdiff_spec.rb
+++ b/spec/components/onpdiff_spec.rb
@@ -33,7 +33,7 @@ describe ONPDiff do
       expect(ONPDiff.new("abc", "acd").short_diff).to eq([["a", :common], ["b", :delete], ["c", :common], ["d", :add]])
     end
 
-    it "returns an array with sequencially similar operations merged" do
+    it "returns an array with sequentially similar operations merged" do
       expect(ONPDiff.new("abcd", "abef").short_diff).to eq([["ab", :common], ["ef", :add], ["cd", :delete]])
     end
 
diff --git a/spec/components/post_action_creator_spec.rb b/spec/components/post_action_creator_spec.rb
index 63e5117537a..dd4ef73f946 100644
--- a/spec/components/post_action_creator_spec.rb
+++ b/spec/components/post_action_creator_spec.rb
@@ -178,7 +178,7 @@ describe PostActionCreator do
           expect(reviewable.reviewable_scores.select(&:pending?).count).to eq(1)
         end
 
-        it "succesfully flags the post if it was reviewed more than 24 hours ago" do
+        it "successfully flags the post if it was reviewed more than 24 hours ago" do
           reviewable.update!(updated_at: 25.hours.ago)
           post.last_version_at = 30.hours.ago
 
@@ -188,7 +188,7 @@ describe PostActionCreator do
           expect(result.reviewable).to be_present
         end
 
-        it "succesfully flags the post if it was edited after being reviewed" do
+        it "successfully flags the post if it was edited after being reviewed" do
           reviewable.update!(updated_at: 10.minutes.ago)
           post.last_version_at = 1.minute.ago
 
diff --git a/spec/components/post_creator_spec.rb b/spec/components/post_creator_spec.rb
index 3f4262a65ae..5827de6ad0c 100644
--- a/spec/components/post_creator_spec.rb
+++ b/spec/components/post_creator_spec.rb
@@ -674,7 +674,7 @@ describe PostCreator do
         SiteSetting.unique_posts_mins = 10
       end
 
-      it "fails for dupe post accross topic" do
+      it "fails for dupe post across topic" do
         first = create_post(raw: "this is a test #{SecureRandom.hex}")
         second = create_post(raw: "this is a test #{SecureRandom.hex}")
 
@@ -1233,7 +1233,7 @@ describe PostCreator do
       DiscourseEvent.off(:topic_created, &@increase_topics)
     end
 
-    it "fires boths event when creating a topic" do
+    it "fires both event when creating a topic" do
       pc = PostCreator.new(user, raw: 'this is the new content for my topic', title: 'this is my new topic title')
       _post = pc.create
       expect(@posts_created).to eq(1)
diff --git a/spec/components/pretty_text_spec.rb b/spec/components/pretty_text_spec.rb
index 1cc6baefaaa..f884df702b4 100644
--- a/spec/components/pretty_text_spec.rb
+++ b/spec/components/pretty_text_spec.rb
@@ -1304,7 +1304,7 @@ HTML
     expect(cooked.split("img").length - 1).to eq(3)
   end
 
-  it "handles emoji boundries correctly" do
+  it "handles emoji boundaries correctly" do
     expect(PrettyText.cook(",:)")).to include("emoji")
     expect(PrettyText.cook(":-)\n")).to include("emoji")
     expect(PrettyText.cook("a :)")).to include("emoji")
@@ -1798,7 +1798,7 @@ HTML
     HTML
   end
 
-  it "has a proper data whitlist on div" do
+  it "has a proper data whitelist on div" do
     cooked = PrettyText.cook("<div data-theme-a='a'>test</div>")
     expect(cooked).to include("data-theme-a")
   end
diff --git a/spec/components/promotion_spec.rb b/spec/components/promotion_spec.rb
index be60cbddca7..ca61fe3568e 100644
--- a/spec/components/promotion_spec.rb
+++ b/spec/components/promotion_spec.rb
@@ -84,7 +84,7 @@ describe Promotion do
         expect(job["args"][0]["message_type"]).to eq("welcome_tl1_user")
       end
 
-      it "does not not send when the user already has the tl1 badge when recalculcating" do
+      it "does not not send when the user already has the tl1 badge when recalculating" do
         SiteSetting.send_tl1_welcome_message = true
         BadgeGranter.grant(Badge.find(1), user)
         stat = user.user_stat
diff --git a/spec/components/search_spec.rb b/spec/components/search_spec.rb
index c6a52dcdd2f..be25dbd0e06 100644
--- a/spec/components/search_spec.rb
+++ b/spec/components/search_spec.rb
@@ -135,7 +135,7 @@ describe Search do
     expect(search.term).to eq('a b c okaylength')
   end
 
-  context 'query sanitizaton' do
+  context 'query sanitization' do
     let!(:post) { Fabricate(:post, raw: 'hello world') }
 
     it 'escapes backslash' do
@@ -1406,7 +1406,7 @@ describe Search do
         raw: 'Relevant Relevant Topic'
       )
 
-      latest_irelevant_topic_post = Fabricate(:post,
+      latest_irrelevant_topic_post = Fabricate(:post,
         topic: latest_topic,
         created_at: today,
         raw: 'Not Relevant'
@@ -1415,14 +1415,14 @@ describe Search do
       # Expecting the default results
       expect(Search.execute('Topic').posts.map(&:id)).to eq([
         old_relevant_topic_post.id,
-        latest_irelevant_topic_post.id,
+        latest_irrelevant_topic_post.id,
         category.topic.first_post.id
       ])
 
       # Expecting the ordered by topic creation results
       expect(Search.execute('Topic order:latest_topic').posts.map(&:id)).to eq([
         category.topic.first_post.id,
-        latest_irelevant_topic_post.id,
+        latest_irrelevant_topic_post.id,
         old_relevant_topic_post.id
       ])
     end
@@ -1667,7 +1667,7 @@ describe Search do
       expect(ts_query).to include("baz")
     end
 
-    it 'esacpes the term correctly' do
+    it 'escapes the term correctly' do
       expect(Search.ts_query(term: 'Title with trailing backslash\\'))
         .to eq("TO_TSQUERY('english', '''Title with trailing backslash\\\\\\\\'':*')")
 
@@ -1801,7 +1801,7 @@ describe Search do
       Fabricate(:post, raw: '場サアマネ織企ういかせ竹域ヱイマ穂基ホ神3予読ずねいぱ松査ス禁多サウ提懸イふ引小43改こょドめ。深とつぐ主思料農ぞかル者杯検める活分えほづぼ白犠')
     end
 
-    it('does not include superflous spaces in blurbs') do
+    it('does not include superfluous spaces in blurbs') do
 
       results = Search.execute('ういかせ竹域', type_filter: 'topic')
       expect(results.posts.length).to eq(1)
diff --git a/spec/components/site_setting_extension_spec.rb b/spec/components/site_setting_extension_spec.rb
index 0180122715e..ba85686135a 100644
--- a/spec/components/site_setting_extension_spec.rb
+++ b/spec/components/site_setting_extension_spec.rb
@@ -5,11 +5,11 @@ require 'rails_helper'
 describe SiteSettingExtension do
 
   # We disable message bus here to avoid a large amount
-  # of uneeded messaging, tests are careful to call refresh
+  # of unneeded messaging, tests are careful to call refresh
   # when they need to.
   #
   # DistributedCache used by locale handler can under certain
-  # cases take a tiny bit to stabalize.
+  # cases take a tiny bit to stabilize.
   #
   # TODO: refactor SiteSettingExtension not to rely on statics in
   # DefaultsProvider
diff --git a/spec/components/slug_spec.rb b/spec/components/slug_spec.rb
index 2ba8062d5e1..99941e0575b 100644
--- a/spec/components/slug_spec.rb
+++ b/spec/components/slug_spec.rb
@@ -159,7 +159,7 @@ describe Slug do
     before { SiteSetting.slug_generation_method = 'encoded' }
     after { SiteSetting.slug_generation_method = 'ascii' }
 
-    it 'generates precentage encoded string' do
+    it 'generates percentage encoded string' do
       expect(Slug.encoded_generator("뉴스피드")).to eq("%EB%89%B4%EC%8A%A4%ED%94%BC%EB%93%9C")
       expect(Slug.encoded_generator("آموزش اضافه کردن لینک اختیاری به هدر")).to eq("%D8%A2%D9%85%D9%88%D8%B2%D8%B4-%D8%A7%D8%B6%D8%A7%D9%81%D9%87-%DA%A9%D8%B1%D8%AF%D9%86-%D9%84%DB%8C%D9%86%DA%A9-%D8%A7%D8%AE%D8%AA%DB%8C%D8%A7%D8%B1%DB%8C-%D8%A8%D9%87-%D9%87%D8%AF%D8%B1")
       expect(Slug.encoded_generator("熱帶風暴畫眉")).to eq("%E7%86%B1%E5%B8%B6%E9%A2%A8%E6%9A%B4%E7%95%AB%E7%9C%89")
diff --git a/spec/components/topic_query_spec.rb b/spec/components/topic_query_spec.rb
index ec6a2f26917..041f519cd60 100644
--- a/spec/components/topic_query_spec.rb
+++ b/spec/components/topic_query_spec.rb
@@ -598,7 +598,7 @@ describe TopicQuery do
 
     end
 
-    context 'after clearring a pinned topic' do
+    context 'after clearing a pinned topic' do
       before do
         pinned_topic.clear_pin_for(user)
       end
@@ -926,7 +926,7 @@ describe TopicQuery do
       let!(:archived_topic) { Fabricate(:topic, user: creator, archived: true) }
       let!(:invisible_topic) { Fabricate(:topic, user: creator, visible: false) }
 
-      it "should omit the closed/archived/invisbiel topics from suggested" do
+      it "should omit the closed/archived/invisible topics from suggested" do
         expect(TopicQuery.new.list_suggested_for(topic).topics).to eq([regular_topic])
       end
     end
@@ -1158,7 +1158,7 @@ describe TopicQuery do
       expect(topics).to contain_exactly(topic1, topic2, topic6)
     end
 
-    it 'should retun the right list for users in the same group' do
+    it 'should return the right list for users in the same group' do
       topics = TopicQuery.new(user).list_group_topics(group).topics
 
       expect(topics).to contain_exactly(topic1, topic2, topic3, topic6)
diff --git a/spec/components/topic_retriever_spec.rb b/spec/components/topic_retriever_spec.rb
index 3bc2ec81b72..e14379f5cce 100644
--- a/spec/components/topic_retriever_spec.rb
+++ b/spec/components/topic_retriever_spec.rb
@@ -25,7 +25,7 @@ describe TopicRetriever do
       end
     end
 
-    context "when topics have been retrieived recently" do
+    context "when topics have been retrieved recently" do
       before do
         topic_retriever.stubs(:retrieved_recently?).returns(true)
       end
@@ -41,7 +41,7 @@ describe TopicRetriever do
         topic_retriever.stubs(:invalid_url?).returns(false)
       end
 
-      context "when topics have been retrieived recently" do
+      context "when topics have been retrieved recently" do
         before do
           topic_retriever.stubs(:retrieved_recently?).returns(true)
         end
@@ -52,7 +52,7 @@ describe TopicRetriever do
         end
       end
 
-      context "when topics have not been retrieived recently" do
+      context "when topics have not been retrieved recently" do
         before do
           topic_retriever.stubs(:retrieved_recently?).returns(false)
         end
diff --git a/spec/components/unread_spec.rb b/spec/components/unread_spec.rb
index d820fb9fc76..a7d4d4a65e0 100644
--- a/spec/components/unread_spec.rb
+++ b/spec/components/unread_spec.rb
@@ -26,7 +26,7 @@ describe Unread do
   end
 
   describe 'staff counts' do
-    it 'shoule correctly return based on staff post number' do
+    it 'should correctly return based on staff post number' do
 
       user.admin = true
 
diff --git a/spec/components/validators/max_emojis_validator_spec.rb b/spec/components/validators/max_emojis_validator_spec.rb
index f15a951db8a..d95bbe9997a 100644
--- a/spec/components/validators/max_emojis_validator_spec.rb
+++ b/spec/components/validators/max_emojis_validator_spec.rb
@@ -21,7 +21,7 @@ describe MaxEmojisValidator do
       validate
       expect(record.errors[:title][0]).to eq(I18n.t("errors.messages.max_emojis", max_emojis_count: 3))
 
-      record.title = ':joy: :blush: :smile: is not only about emojis: Happyness::start()'
+      record.title = ':joy: :blush: :smile: is not only about emojis: Happiness::start()'
       validate
       expect(record.valid?).to be true
     end
diff --git a/spec/fixtures/emails/paragraphs.eml b/spec/fixtures/emails/paragraphs.eml
index 7fb2bd3733e..f8ee78061cc 100644
--- a/spec/fixtures/emails/paragraphs.eml
+++ b/spec/fixtures/emails/paragraphs.eml
@@ -8,5 +8,5 @@ Content-Type: text/plain; charset=UTF-8
 
 Do you like liquorice?
 
-I really like them. One could even say that I am *addicted* to liquorice. Anf if
+I really like them. One could even say that I am *addicted* to liquorice. And if
 you can mix it up with some anise, then I'm in heaven ;)
diff --git a/spec/jobs/bulk_invite_spec.rb b/spec/jobs/bulk_invite_spec.rb
index 676d93c8fa6..bfaa49c9207 100644
--- a/spec/jobs/bulk_invite_spec.rb
+++ b/spec/jobs/bulk_invite_spec.rb
@@ -81,7 +81,7 @@ describe Jobs::BulkInvite do
       expect(existing_user.reload.groups).to eq([group1])
     end
 
-    it 'can create staged users and prepulate user fields' do
+    it 'can create staged users and prepopulate user fields' do
       user_field = Fabricate(:user_field, name: "Location")
       user_field_color = Fabricate(:user_field, field_type: "dropdown", name: "Color")
       user_field_color.user_field_options.create!(value: "Red")
diff --git a/spec/jobs/jobs_spec.rb b/spec/jobs/jobs_spec.rb
index 5ee5ff09a77..113f8e57889 100644
--- a/spec/jobs/jobs_spec.rb
+++ b/spec/jobs/jobs_spec.rb
@@ -42,7 +42,7 @@ describe Jobs do
         end
         expect(jobs.length).to eq(2)
 
-        # Failed transation
+        # Failed transaction
         ActiveRecord::Base.transaction do
           Jobs.enqueue(:process_post, post_id: 1)
           raise ActiveRecord::Rollback
diff --git a/spec/lib/backup_restore/meta_data_handler_spec.rb b/spec/lib/backup_restore/meta_data_handler_spec.rb
index c9ba6cbaffc..7d6ddc8ad43 100644
--- a/spec/lib/backup_restore/meta_data_handler_spec.rb
+++ b/spec/lib/backup_restore/meta_data_handler_spec.rb
@@ -34,9 +34,9 @@ describe BackupRestore::MetaDataHandler do
     end
 
     it "raises an exception when the metadata file contains invalid JSON" do
-      currupt_metadata = '{"version":20160329101122'
+      corrupt_metadata = '{"version":20160329101122'
 
-      with_metadata_file(currupt_metadata) do |dir|
+      with_metadata_file(corrupt_metadata) do |dir|
         expect { validate_metadata(backup_filename, dir) }
           .to raise_error(BackupRestore::MetaDataError)
       end
diff --git a/spec/lib/backup_restore/shared_examples_for_backup_store.rb b/spec/lib/backup_restore/shared_examples_for_backup_store.rb
index f6d3fbab3d2..344fb17f2fb 100644
--- a/spec/lib/backup_restore/shared_examples_for_backup_store.rb
+++ b/spec/lib/backup_restore/shared_examples_for_backup_store.rb
@@ -266,7 +266,7 @@ shared_examples "remote backup store" do
         expect(url).to match(upload_url_regex("default", filename, multisite: false))
       end
 
-      it "raises an exeption when a file with same filename exists" do
+      it "raises an exception when a file with same filename exists" do
         expect { store.generate_upload_url(backup1.filename) }
           .to raise_exception(BackupRestore::BackupStore::BackupFileExists)
       end
diff --git a/spec/lib/bookmark_manager_spec.rb b/spec/lib/bookmark_manager_spec.rb
index bf9f1d2f54e..11cbf642b16 100644
--- a/spec/lib/bookmark_manager_spec.rb
+++ b/spec/lib/bookmark_manager_spec.rb
@@ -109,7 +109,7 @@ RSpec.describe BookmarkManager do
       end
     end
 
-    context "when the post is inaccessable for the user" do
+    context "when the post is inaccessible for the user" do
       before do
         post.trash!
       end
@@ -118,7 +118,7 @@ RSpec.describe BookmarkManager do
       end
     end
 
-    context "when the topic is inaccessable for the user" do
+    context "when the topic is inaccessible for the user" do
       before do
         post.topic.update(category: Fabricate(:private_category, group: Fabricate(:group)))
       end
@@ -182,7 +182,7 @@ RSpec.describe BookmarkManager do
       )
     end
 
-    it "saves the time and new reminder type and new name sucessfully" do
+    it "saves the time and new reminder type and new name successfully" do
       update_bookmark
       bookmark.reload
       expect(bookmark.name).to eq(new_name)
diff --git a/spec/lib/webauthn/challenge_generator_spec.rb b/spec/lib/webauthn/challenge_generator_spec.rb
index a0b7609ecfc..74349356a12 100644
--- a/spec/lib/webauthn/challenge_generator_spec.rb
+++ b/spec/lib/webauthn/challenge_generator_spec.rb
@@ -15,7 +15,7 @@ describe Webauthn::ChallengeGenerator do
     describe "#commit_to_session" do
       let(:user) { Fabricate(:user) }
 
-      it "stores the challenge, rpid, and name in the provided session object" do
+      it "stores the challenge, rp id, and rp name in the provided session object" do
         secure_session = {}
         generated_session = Webauthn::ChallengeGenerator.generate
         generated_session.commit_to_session(secure_session, user)
diff --git a/spec/models/about_spec.rb b/spec/models/about_spec.rb
index 4659ff7a208..3b8ee597abc 100644
--- a/spec/models/about_spec.rb
+++ b/spec/models/about_spec.rb
@@ -5,7 +5,7 @@ require 'rails_helper'
 describe About do
 
   describe 'stats cache' do
-    include_examples 'stats cachable'
+    include_examples 'stats cacheable'
   end
 
   describe "#category_moderators" do
diff --git a/spec/models/admin_dashboard_problem_spec.rb b/spec/models/admin_dashboard_problem_spec.rb
index 84b596e17b3..b2d3a1c0ff8 100644
--- a/spec/models/admin_dashboard_problem_spec.rb
+++ b/spec/models/admin_dashboard_problem_spec.rb
@@ -221,7 +221,7 @@ describe AdminDashboardData do
   end
 
   describe 'stats cache' do
-    include_examples 'stats cachable'
+    include_examples 'stats cacheable'
   end
 
   describe '#problem_message_check' do
diff --git a/spec/models/category_list_spec.rb b/spec/models/category_list_spec.rb
index ea5c839aa8e..81a0fe33101 100644
--- a/spec/models/category_list_spec.rb
+++ b/spec/models/category_list_spec.rb
@@ -120,7 +120,7 @@ describe CategoryList do
         expect(category.notification_level).to eq(NotificationLevels.all[:regular])
       end
 
-      it "returns the users notication level" do
+      it "returns the users notification level" do
         CategoryUser.set_notification_level_for_category(user, NotificationLevels.all[:watching], topic_category.id)
         category_list = CategoryList.new(Guardian.new(user))
         category = category_list.categories.find { |c| c.id == topic_category.id }
@@ -128,7 +128,7 @@ describe CategoryList do
         expect(category.notification_level).to eq(NotificationLevels.all[:watching])
       end
 
-      it "returns default notication level for anonymous users" do
+      it "returns default notification level for anonymous users" do
         category_list = CategoryList.new(Guardian.new(nil))
         category = category_list.categories.find { |c| c.id == topic_category.id }
 
diff --git a/spec/models/email_token_spec.rb b/spec/models/email_token_spec.rb
index 46db9c98de0..aa6dfac6d70 100644
--- a/spec/models/email_token_spec.rb
+++ b/spec/models/email_token_spec.rb
@@ -11,7 +11,7 @@ describe EmailToken do
   context '#create' do
     fab!(:user) { Fabricate(:user, active: false) }
     let!(:original_token) { user.email_tokens.first }
-    let!(:email_token) { user.email_tokens.create(email: 'bubblegum@adevnturetime.ooo') }
+    let!(:email_token) { user.email_tokens.create(email: 'bubblegum@adventuretime.ooo') }
 
     it 'should create the email token' do
       expect(email_token).to be_present
diff --git a/spec/models/notification_spec.rb b/spec/models/notification_spec.rb
index 138ca3d76e2..a97537a31aa 100644
--- a/spec/models/notification_spec.rb
+++ b/spec/models/notification_spec.rb
@@ -298,7 +298,7 @@ describe Notification do
       expect(user.unread_notifications).to eq(0)
       expect(user.total_unread_notifications).to eq(3)
       # NOTE: because of deprecation this will be equal to unread_high_priority_notifications,
-      #       to be remonved in 2.5
+      #       to be removed in 2.5
       expect(user.unread_private_messages).to eq(2)
       expect(user.unread_high_priority_notifications).to eq(2)
     end
diff --git a/spec/models/post_action_spec.rb b/spec/models/post_action_spec.rb
index dc71f1e001f..b81b73504b2 100644
--- a/spec/models/post_action_spec.rb
+++ b/spec/models/post_action_spec.rb
@@ -253,7 +253,7 @@ describe PostAction do
       admin4 = Fabricate(:admin)
       PostActionCreator.like(admin4, post)
 
-      # first happend within the same day, no need to notify
+      # first happened within the same day, no need to notify
       expect(Notification.where(post_number: 1, topic_id: post.topic_id).count)
         .to eq(2)
     end
@@ -419,7 +419,7 @@ describe PostAction do
       end.to_not change { Notification.count }
     end
 
-    it "should generate a notification if liker is an admin irregardles of \
+    it "should generate a notification if liker is an admin irregardless of \
       muting" do
 
       MutedUser.create!(user_id: post.user.id, muted_user_id: admin.id)
@@ -663,7 +663,7 @@ describe PostAction do
       expect(result.reviewable.payload['targets_topic']).to eq(false)
     end
 
-    it "will unhide the post when a moderator undos the flag on which s/he took action" do
+    it "will unhide the post when a moderator undoes the flag on which s/he took action" do
       Discourse.stubs(:site_contact_user).returns(admin)
 
       post = create_post
diff --git a/spec/models/report_spec.rb b/spec/models/report_spec.rb
index 0b4c330af82..36ffeb0aa3f 100644
--- a/spec/models/report_spec.rb
+++ b/spec/models/report_spec.rb
@@ -224,7 +224,7 @@ describe Report do
         end
 
         it 'returns a report with data' do
-          # expected number of recoords
+          # expected number of records
           expect(report.data.count).to eq 4
 
           # sorts the data from oldest to latest dates
@@ -724,7 +724,7 @@ describe Report do
             post.revise(sam, raw: 'updated body')
           end
 
-          it "doesn't count a revison on your own post" do
+          it "doesn't count a revision on your own post" do
             expect(report.data[0][:revision_count]).to eq(1)
             expect(report.data[0][:username]).to eq('sam')
           end
diff --git a/spec/models/reviewable_user_spec.rb b/spec/models/reviewable_user_spec.rb
index b63c4901c95..a16c6c2ac4b 100644
--- a/spec/models/reviewable_user_spec.rb
+++ b/spec/models/reviewable_user_spec.rb
@@ -135,7 +135,7 @@ RSpec.describe ReviewableUser, type: :model do
         reviewable.perform(moderator, :reject_user_block, reject_reason: "reject reason")
       end
 
-      it "optionaly sends email with reject reason" do
+      it "optionally sends email with reject reason" do
         SiteSetting.must_approve_users = true
         Jobs::CriticalUserEmail.any_instance.expects(:execute).with(type: :signup_after_reject, user_id: reviewable.target_id, reject_reason: "reject reason").once
         reviewable.perform(moderator, :reject_user_block, reject_reason: "reject reason", send_email: true)
diff --git a/spec/models/site_setting_spec.rb b/spec/models/site_setting_spec.rb
index cf9b5174b45..7a815848787 100644
--- a/spec/models/site_setting_spec.rb
+++ b/spec/models/site_setting_spec.rb
@@ -196,7 +196,7 @@ describe SiteSetting do
   end
 
   describe 'cached settings' do
-    it 'should recalcualte cached setting when dependent settings are changed' do
+    it 'should recalculate cached setting when dependent settings are changed' do
       SiteSetting.blocked_attachment_filenames = 'foo'
       expect(SiteSetting.blocked_attachment_filenames_regex).to eq(/foo/)
 
diff --git a/spec/models/topic_spec.rb b/spec/models/topic_spec.rb
index 57ff44c4f62..b797e1cb07b 100644
--- a/spec/models/topic_spec.rb
+++ b/spec/models/topic_spec.rb
@@ -2118,7 +2118,7 @@ describe Topic do
       expect(topic.all_allowed_users).to include moderator
     end
 
-    it 'includes moderators if offical warning' do
+    it 'includes moderators if official warning' do
       topic.stubs(:subtype).returns(TopicSubtype.moderator_warning)
       topic.stubs(:private_message?).returns(true)
       expect(topic.all_allowed_users).to include moderator
@@ -2307,10 +2307,10 @@ describe Topic do
     end
   end
 
-  describe ".count_exceeds_minimun?" do
+  describe ".count_exceeds_minimum?" do
     before { SiteSetting.minimum_topics_similar = 20 }
 
-    context "when Topic count is geater than minimum_topics_similar" do
+    context "when Topic count is greater than minimum_topics_similar" do
       it "should be true" do
         Topic.stubs(:count).returns(30)
         expect(Topic.count_exceeds_minimum?).to be_truthy
@@ -2334,7 +2334,7 @@ describe Topic do
       expect(topic.expandable_first_post?).to eq(false)
     end
 
-    describe 'with an emeddable host' do
+    describe 'with an embeddable host' do
       before do
         Fabricate(:embeddable_host)
         SiteSetting.embed_truncate = true
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 600d7f1c746..2f5bdfc90dd 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -679,7 +679,7 @@ describe User do
       expect(User.username_available?('tESt')).to eq(false)
     end
 
-    it 'returns true when reserved username is explicity allowed' do
+    it 'returns true when reserved username is explicitly allowed' do
       SiteSetting.reserved_usernames = 'test|donkey'
 
       expect(User.username_available?(
@@ -727,7 +727,7 @@ describe User do
       expect(User.reserved_username?('test')).to eq(true)
     end
 
-    it 'should not allow usernames matched against an expession' do
+    it 'should not allow usernames matched against an expression' do
       SiteSetting.reserved_usernames = "test)|*admin*|foo*|*bar|abc.def|löwe|ka\u0308fer"
 
       expect(User.reserved_username?('test')).to eq(false)
@@ -1901,7 +1901,7 @@ describe User do
 
       expect(message.data[:unread_notifications]).to eq(1)
       # NOTE: because of deprecation this will be equal to unread_high_priority_notifications,
-      #       to be remonved in 2.5
+      #       to be removed in 2.5
       expect(message.data[:unread_private_messages]).to eq(2)
       expect(message.data[:unread_high_priority_notifications]).to eq(2)
     end
@@ -2359,7 +2359,7 @@ describe User do
           expect(User.system_avatar_template("बहुत")).to match(%r|/letter_avatar_proxy/v\d/letter/%E0%A4%AC/ea5d25/{size}.png|)
         end
 
-        it "substitues {username} with the URL encoded username" do
+        it "substitutes {username} with the URL encoded username" do
           SiteSetting.external_system_avatars_url = "https://{hostname}/{username}.png"
           expect(User.system_avatar_template("बहुत")).to eq("https://#{Discourse.current_hostname}/%E0%A4%AC%E0%A4%B9%E0%A5%81%E0%A4%A4.png")
         end
diff --git a/spec/models/username_validator_spec.rb b/spec/models/username_validator_spec.rb
index 5bf51119969..ab055ccacf6 100644
--- a/spec/models/username_validator_spec.rb
+++ b/spec/models/username_validator_spec.rb
@@ -37,7 +37,7 @@ describe UsernameValidator do
                      error_message: I18n.t(:'user.username.short', min: 4))
     end
 
-    it 'is valid when the username has the minimum lenght' do
+    it 'is valid when the username has the minimum length' do
       SiteSetting.min_username_length = 4
 
       expect_valid('abcd')
@@ -50,7 +50,7 @@ describe UsernameValidator do
                      error_message: I18n.t(:'user.username.long', max: 8))
     end
 
-    it 'is valid when the username has the maximum lenght' do
+    it 'is valid when the username has the maximum length' do
       SiteSetting.max_username_length = 8
 
       expect_valid('abcdefgh')
@@ -122,7 +122,7 @@ describe UsernameValidator do
                        error_message: I18n.t(:'user.username.short', min: 3))
       end
 
-      it 'is valid when the username has the minimum lenght' do
+      it 'is valid when the username has the minimum length' do
         SiteSetting.min_username_length = 2
 
         expect_valid('পাখি', 'طائر')
@@ -135,7 +135,7 @@ describe UsernameValidator do
                        error_message: I18n.t(:'user.username.long', max: 8))
       end
 
-      it 'is valid when the username has the maximum lenght' do
+      it 'is valid when the username has the maximum length' do
         SiteSetting.max_username_length = 9
 
         expect_valid('Дровосек', 'چوب-لباسی', 'தமிழ்-தமிழ்')
diff --git a/spec/models/web_hook_spec.rb b/spec/models/web_hook_spec.rb
index 492cb83a7d8..570ba6a95c6 100644
--- a/spec/models/web_hook_spec.rb
+++ b/spec/models/web_hook_spec.rb
@@ -40,7 +40,7 @@ describe WebHook do
     fab!(:post_hook) { Fabricate(:web_hook, payload_url: " https://example.com ") }
     fab!(:topic_hook) { Fabricate(:topic_web_hook) }
 
-    it "removes whitspace from payload_url before saving" do
+    it "removes whitespace from payload_url before saving" do
       expect(post_hook.payload_url).to eq("https://example.com")
     end
 
diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb
index 1c6c80d27d0..fc996dabf36 100644
--- a/spec/rails_helper.rb
+++ b/spec/rails_helper.rb
@@ -97,7 +97,7 @@ module TestSetup
   # This is run before each test and before each before_all block
   def self.test_setup(x = nil)
     # TODO not sure about this, we could use a mock redis implementation here:
-    #   this gives us really clean "flush" semantics, howere the side-effect is that
+    #   this gives us really clean "flush" semantics, however the side-effect is that
     #   we are no longer using a clean redis implementation, a preferable solution may
     #   be simply flushing before tests, trouble is that redis may be reused with dev
     #   so that would mean the dev would act weird
diff --git a/spec/requests/admin/reports_controller_spec.rb b/spec/requests/admin/reports_controller_spec.rb
index 1138b1be6fc..80f72176d60 100644
--- a/spec/requests/admin/reports_controller_spec.rb
+++ b/spec/requests/admin/reports_controller_spec.rb
@@ -32,7 +32,7 @@ describe Admin::ReportsController do
       end
 
       context "invalid params" do
-        context "inexisting report" do
+        context "nonexistent report" do
           it "returns not found reports" do
             get "/admin/reports/bulk.json", params: {
               reports: {
diff --git a/spec/requests/admin/users_controller_spec.rb b/spec/requests/admin/users_controller_spec.rb
index e756c6cbd26..1fec5579b3c 100644
--- a/spec/requests/admin/users_controller_spec.rb
+++ b/spec/requests/admin/users_controller_spec.rb
@@ -32,7 +32,7 @@ RSpec.describe Admin::UsersController do
         end
       end
 
-      it "logs only 1 enty" do
+      it "logs only 1 entry" do
         expect do
           get "/admin/users/list.json", params: { show_emails: "true" }
         end.to change { UserHistory.where(action: UserHistory.actions[:check_email], acting_user_id: admin.id).count }.by(1)
@@ -98,7 +98,7 @@ RSpec.describe Admin::UsersController do
 
     let(:evil_trout) { Fabricate(:evil_trout) }
 
-    it "does nothing without uesrs" do
+    it "does nothing without users" do
       put "/admin/users/approve-bulk.json"
       evil_trout.reload
       expect(response.status).to eq(200)
diff --git a/spec/requests/api/posts_spec.rb b/spec/requests/api/posts_spec.rb
index fd45f7997a3..a9e16cf834f 100644
--- a/spec/requests/api/posts_spec.rb
+++ b/spec/requests/api/posts_spec.rb
@@ -118,7 +118,7 @@ describe 'posts' do
 
   path '/posts/{id}.json' do
 
-    get 'Retreive a single post' do
+    get 'Retrieve a single post' do
       tags 'Posts'
       parameter name: 'Api-Key', in: :header, type: :string, required: true
       parameter name: 'Api-Username', in: :header, type: :string, required: true
diff --git a/spec/requests/application_controller_spec.rb b/spec/requests/application_controller_spec.rb
index 2e76f30a8cd..fa2e8d15aa6 100644
--- a/spec/requests/application_controller_spec.rb
+++ b/spec/requests/application_controller_spec.rb
@@ -260,7 +260,7 @@ RSpec.describe ApplicationController do
       if (log.include? 'exception app middleware')
         # heisentest diagnostics
         puts
-        puts "EXTRA DIAGNOSTICS FOR INTERMITENT TEST FAIL"
+        puts "EXTRA DIAGNOSTICS FOR INTERMITTENT TEST FAIL"
         puts log
         puts ">> action_dispatch.exception"
         ex = request.env['action_dispatch.exception']
diff --git a/spec/requests/categories_controller_spec.rb b/spec/requests/categories_controller_spec.rb
index fc170246928..ffbf60843c9 100644
--- a/spec/requests/categories_controller_spec.rb
+++ b/spec/requests/categories_controller_spec.rb
@@ -333,11 +333,11 @@ describe CategoriesController do
       end
 
       it "returns 422 if email_in address is already in use for other category" do
-        _other_category = Fabricate(:category, name: "Other", email_in: "mail@examle.com")
+        _other_category = Fabricate(:category, name: "Other", email_in: "mail@example.com")
 
         put "/categories/#{category.id}.json", params: {
           name: "Email",
-          email_in: "mail@examle.com",
+          email_in: "mail@example.com",
           color: "ff0",
           text_color: "fff",
         }
diff --git a/spec/requests/extra_locales_controller_spec.rb b/spec/requests/extra_locales_controller_spec.rb
index 7d81ec890e8..4fad83de519 100644
--- a/spec/requests/extra_locales_controller_spec.rb
+++ b/spec/requests/extra_locales_controller_spec.rb
@@ -57,7 +57,7 @@ describe ExtraLocalesController do
               "admin" => {
                 "site_settings" => {
                   "categories" => {
-                    "github_badges" => "Github Badges"
+                    "github_badges" => "GitHub Badges"
                   }
                 }
               }
diff --git a/spec/requests/groups_controller_spec.rb b/spec/requests/groups_controller_spec.rb
index 817ef5c63d0..fd5adca9fe5 100644
--- a/spec/requests/groups_controller_spec.rb
+++ b/spec/requests/groups_controller_spec.rb
@@ -1102,7 +1102,7 @@ describe GroupsController do
     fab!(:group) { Fabricate(:group) }
 
     context 'when user is not signed in' do
-      it 'should be fobidden' do
+      it 'should be forbidden' do
         put "/groups/#{group.id}/members.json", params: { usernames: "bob" }
         expect(response).to be_forbidden
 
@@ -1111,7 +1111,7 @@ describe GroupsController do
       end
 
       context 'public group' do
-        it 'should be fobidden' do
+        it 'should be forbidden' do
           group.update!(
             public_admission: true,
             public_exit: true
@@ -1447,7 +1447,7 @@ describe GroupsController do
           expect(response.status).to eq(200)
         end
 
-        it 'should not allow an underprivilege user to add another user to a group' do
+        it 'should not allow an underprivileged user to add another user to a group' do
           sign_in(user)
 
           put "/groups/#{group.id}/members.json",
@@ -1549,7 +1549,7 @@ describe GroupsController do
             expect(response.status).to eq(200)
           end
 
-          it 'should not allow a underprivilege user to leave a group for another user' do
+          it 'should not allow a underprivileged user to leave a group for another user' do
             sign_in(user)
 
             delete "/groups/#{group.id}/members.json",
diff --git a/spec/requests/hashtags_controller_spec.rb b/spec/requests/hashtags_controller_spec.rb
index 16d736d5c25..fc67091e207 100644
--- a/spec/requests/hashtags_controller_spec.rb
+++ b/spec/requests/hashtags_controller_spec.rb
@@ -49,7 +49,7 @@ describe HashtagsController do
           sign_in(admin)
         end
 
-        it "returns restricted categories and hidden tagss" do
+        it "returns restricted categories and hidden tags" do
           group.add(admin)
 
           get "/hashtags.json", params: { slugs: [private_category.slug, hidden_tag.name] }
diff --git a/spec/requests/permalinks_controller_spec.rb b/spec/requests/permalinks_controller_spec.rb
index 5f6c6efa922..549ec647f2e 100644
--- a/spec/requests/permalinks_controller_spec.rb
+++ b/spec/requests/permalinks_controller_spec.rb
@@ -4,7 +4,7 @@ require 'rails_helper'
 
 describe PermalinksController do
   fab!(:topic) { Fabricate(:topic) }
-  fab!(:permalink) { Fabricate(:permalink, url: "deadroutee/topic/546") }
+  fab!(:permalink) { Fabricate(:permalink, url: "deadroute/topic/546") }
 
   describe 'show' do
     it "should redirect to a permalink's target_url with status 301" do
diff --git a/spec/requests/post_readers_controller_spec.rb b/spec/requests/post_readers_controller_spec.rb
index 4916f54cac7..2b2dbe6ba71 100644
--- a/spec/requests/post_readers_controller_spec.rb
+++ b/spec/requests/post_readers_controller_spec.rb
@@ -48,7 +48,7 @@ describe PostReadersController do
         assert_reader_is_correctly_serialized(reader_data, reader, @post)
       end
 
-      it 'return an empty list when nodobody read unti that post' do
+      it 'return an empty list when nodobody read until that post' do
         TopicUser.create!(user: reader, topic: @group_message, last_read_post_number: 1)
 
         get '/post_readers.json', params: { id: @post.id }
diff --git a/spec/requests/posts_controller_spec.rb b/spec/requests/posts_controller_spec.rb
index a0dfe836610..68a0ce008e9 100644
--- a/spec/requests/posts_controller_spec.rb
+++ b/spec/requests/posts_controller_spec.rb
@@ -577,7 +577,7 @@ describe PostsController do
       before do
         Fabricate(:bookmark, user: user, post: Fabricate(:post, topic: post.topic), topic: post.topic)
       end
-      it "marks topic_bookmaked as true" do
+      it "marks topic_bookmarked as true" do
         delete "/posts/#{post.id}/bookmark.json"
         expect(response.parsed_body['topic_bookmarked']).to eq(true)
       end
@@ -1903,7 +1903,7 @@ describe PostsController do
   end
 
   describe '#cooked' do
-    it 'returns the cooked conent' do
+    it 'returns the cooked content' do
       post = Fabricate(:post, cooked: "WAt")
       get "/posts/#{post.id}/cooked.json"
 
diff --git a/spec/requests/reviewables_controller_spec.rb b/spec/requests/reviewables_controller_spec.rb
index 5a2abc23528..c277a5eb2fe 100644
--- a/spec/requests/reviewables_controller_spec.rb
+++ b/spec/requests/reviewables_controller_spec.rb
@@ -357,7 +357,7 @@ describe ReviewablesController do
         expect(response.code).to eq("404")
       end
 
-      it "validates the presenece of an action" do
+      it "validates the presence of an action" do
         put "/review/#{reviewable.id}/perform/nope.json?version=#{reviewable.version}"
         expect(response.code).to eq("403")
       end
diff --git a/spec/requests/search_controller_spec.rb b/spec/requests/search_controller_spec.rb
index 6af41183206..be85a71a354 100644
--- a/spec/requests/search_controller_spec.rb
+++ b/spec/requests/search_controller_spec.rb
@@ -534,7 +534,7 @@ describe SearchController do
       expect(data["posts"][3]["id"]).to eq(very_low_priority_post.id)
     end
 
-    it "doesn't sort posts with search piority when query with order" do
+    it "doesn't sort posts with search priority when query with order" do
       get "/search.json", params: { q: 'status:open order:latest Priority Post' }
       expect(response.status).to eq(200)
       data = response.parsed_body
@@ -601,7 +601,7 @@ describe SearchController do
       SearchLog.clear_debounce_cache!
     end
 
-    it "doesn't work wthout the necessary parameters" do
+    it "doesn't work without the necessary parameters" do
       post "/search/click.json"
       expect(response.status).to eq(400)
     end
diff --git a/spec/requests/session_controller_spec.rb b/spec/requests/session_controller_spec.rb
index b065fd7e50e..6bf7b0e05a5 100644
--- a/spec/requests/session_controller_spec.rb
+++ b/spec/requests/session_controller_spec.rb
@@ -495,7 +495,7 @@ RSpec.describe SessionController do
       expect(session[:current_user_id]).to be_blank
     end
 
-    it "works in developmenet mode" do
+    it "works in development mode" do
       Rails.env.stubs(:development?).returns(true)
       get "/session/#{user.username}/become.json"
       expect(response).to be_redirect
@@ -543,7 +543,7 @@ RSpec.describe SessionController do
       sso
     end
 
-    it 'does not create superflous auth tokens when already logged in' do
+    it 'does not create superfluous auth tokens when already logged in' do
       user = Fabricate(:user)
       sign_in(user)
 
@@ -2188,7 +2188,7 @@ RSpec.describe SessionController do
 
   describe '#current' do
     context "when not logged in" do
-      it "retuns 404" do
+      it "returns 404" do
         get "/session/current.json"
         expect(response.status).to eq(404)
       end
diff --git a/spec/requests/tags_controller_spec.rb b/spec/requests/tags_controller_spec.rb
index 0232aa3c2b4..6c50a053907 100644
--- a/spec/requests/tags_controller_spec.rb
+++ b/spec/requests/tags_controller_spec.rb
@@ -105,7 +105,7 @@ describe TagsController do
     end
 
     context "when user can admin tags" do
-      it "succesfully retrieve all tags" do
+      it "successfully retrieve all tags" do
         sign_in(admin)
 
         get "/tags.json"
diff --git a/spec/requests/theme_javascripts_controller_spec.rb b/spec/requests/theme_javascripts_controller_spec.rb
index d1d13a6dd9a..a8716b7536a 100644
--- a/spec/requests/theme_javascripts_controller_spec.rb
+++ b/spec/requests/theme_javascripts_controller_spec.rb
@@ -24,7 +24,7 @@ describe ThemeJavascriptsController do
       get "/theme-javascripts/#{digest}.js"
     end
 
-    it 'only accepts 40-char hexdecimal digest name' do
+    it 'only accepts 40-char hexadecimal digest name' do
       update_digest_and_get('0123456789abcdefabcd0123456789abcdefabcd')
       expect(response.status).to eq(200)
 
diff --git a/spec/requests/topics_controller_spec.rb b/spec/requests/topics_controller_spec.rb
index cfb00692221..bd4e31e2938 100644
--- a/spec/requests/topics_controller_spec.rb
+++ b/spec/requests/topics_controller_spec.rb
@@ -1767,14 +1767,14 @@ RSpec.describe TopicsController do
       let(:deleted_topic) { Fabricate(:deleted_topic) }
       let(:deleted_secure_topic) { Fabricate(:topic, category: secure_category, deleted_at: 1.day.ago) }
       let(:deleted_private_topic) { Fabricate(:private_message_topic, user: allowed_user, deleted_at: 1.day.ago) }
-      let!(:nonexist_topic_id) { Topic.last.id + 10000 }
+      let!(:nonexistent_topic_id) { Topic.last.id + 10000 }
       fab!(:secure_accessible_topic) { Fabricate(:topic, category: accessible_category) }
 
       shared_examples "various scenarios" do |expected|
         expected.each do |key, value|
           it "returns #{value} for #{key}" do
-            slug = key == :nonexist ? "garbage-slug" : send(key.to_s).slug
-            topic_id = key == :nonexist ? nonexist_topic_id : send(key.to_s).id
+            slug = key == :nonexistent ? "garbage-slug" : send(key.to_s).slug
+            topic_id = key == :nonexistent ? nonexistent_topic_id : send(key.to_s).id
             get "/t/#{slug}/#{topic_id}.json"
             expect(response.status).to eq(value)
           end
@@ -1800,7 +1800,7 @@ RSpec.describe TopicsController do
             deleted_topic: 404,
             deleted_secure_topic: 404,
             deleted_private_topic: 404,
-            nonexist: 404,
+            nonexistent: 404,
             secure_accessible_topic: 404
           }
           include_examples "various scenarios", expected
@@ -1817,7 +1817,7 @@ RSpec.describe TopicsController do
             deleted_topic: 302,
             deleted_secure_topic: 302,
             deleted_private_topic: 302,
-            nonexist: 302,
+            nonexistent: 302,
             secure_accessible_topic: 302
           }
           include_examples "various scenarios", expected
@@ -1835,7 +1835,7 @@ RSpec.describe TopicsController do
             deleted_topic: 404,
             deleted_secure_topic: 404,
             deleted_private_topic: 404,
-            nonexist: 404,
+            nonexistent: 404,
             secure_accessible_topic: 404
           }
           include_examples "various scenarios", expected
@@ -1853,7 +1853,7 @@ RSpec.describe TopicsController do
             deleted_topic: 404,
             deleted_secure_topic: 404,
             deleted_private_topic: 404,
-            nonexist: 404,
+            nonexistent: 404,
             secure_accessible_topic: 404
           }
           include_examples "various scenarios", expected
@@ -1871,7 +1871,7 @@ RSpec.describe TopicsController do
             deleted_topic: 200,
             deleted_secure_topic: 404,
             deleted_private_topic: 404,
-            nonexist: 404,
+            nonexistent: 404,
             secure_accessible_topic: 404
           }
           include_examples "various scenarios", expected
@@ -1889,7 +1889,7 @@ RSpec.describe TopicsController do
             deleted_topic: 200,
             deleted_secure_topic: 200,
             deleted_private_topic: 200,
-            nonexist: 404,
+            nonexistent: 404,
             secure_accessible_topic: 200
           }
           include_examples "various scenarios", expected
@@ -1909,7 +1909,7 @@ RSpec.describe TopicsController do
             deleted_topic: 410,
             deleted_secure_topic: 403,
             deleted_private_topic: 403,
-            nonexist: 404,
+            nonexistent: 404,
             secure_accessible_topic: 403
           }
           include_examples "various scenarios", expected
@@ -1926,7 +1926,7 @@ RSpec.describe TopicsController do
             deleted_topic: 302,
             deleted_secure_topic: 302,
             deleted_private_topic: 302,
-            nonexist: 302,
+            nonexistent: 302,
             secure_accessible_topic: 302
           }
           include_examples "various scenarios", expected
@@ -1944,7 +1944,7 @@ RSpec.describe TopicsController do
             deleted_topic: 410,
             deleted_secure_topic: 403,
             deleted_private_topic: 403,
-            nonexist: 404,
+            nonexistent: 404,
             secure_accessible_topic: 403
           }
           include_examples "various scenarios", expected
@@ -1962,7 +1962,7 @@ RSpec.describe TopicsController do
             deleted_topic: 410,
             deleted_secure_topic: 410,
             deleted_private_topic: 410,
-            nonexist: 404,
+            nonexistent: 404,
             secure_accessible_topic: 403
           }
           include_examples "various scenarios", expected
@@ -1980,7 +1980,7 @@ RSpec.describe TopicsController do
             deleted_topic: 200,
             deleted_secure_topic: 403,
             deleted_private_topic: 403,
-            nonexist: 404,
+            nonexistent: 404,
             secure_accessible_topic: 403
           }
           include_examples "various scenarios", expected
@@ -1998,7 +1998,7 @@ RSpec.describe TopicsController do
             deleted_topic: 200,
             deleted_secure_topic: 200,
             deleted_private_topic: 200,
-            nonexist: 404,
+            nonexistent: 404,
             secure_accessible_topic: 200
           }
           include_examples "various scenarios", expected
@@ -3776,7 +3776,7 @@ RSpec.describe TopicsController do
         freeze_time page3_time
         Fabricate(:post, topic: topic)
 
-        # ugly, but no inteface to set this and we don't want to create
+        # ugly, but no interface to set this and we don't want to create
         # 100 posts to test this thing
         TopicView.stubs(:chunk_size).returns(2)
 
@@ -3852,7 +3852,7 @@ RSpec.describe TopicsController do
         end
       end
 
-      it "should fail for non-existend topic" do
+      it "should fail for non-existent topic" do
         max_id = Topic.maximum(:id)
         sign_in(admin)
         put "/t/#{max_id + 1}/reset-bump-date.json"
diff --git a/spec/requests/users_controller_spec.rb b/spec/requests/users_controller_spec.rb
index e7430a9a6ca..12aa1a9d733 100644
--- a/spec/requests/users_controller_spec.rb
+++ b/spec/requests/users_controller_spec.rb
@@ -633,7 +633,7 @@ describe UsersController do
         post "/u.json", params: {
           name: @user.name,
           username: @user.username,
-          password: 'tesing12352343'
+          password: 'testing12352343'
         }
         expect(response.status).to eq(400)
       end
@@ -1369,7 +1369,7 @@ describe UsersController do
     end
 
     context 'while logged in' do
-      let(:old_username) { "OrigUsrname" }
+      let(:old_username) { "OrigUsername" }
       let(:new_username) { "#{old_username}1234" }
       let(:user) { Fabricate(:user, username: old_username) }
 
@@ -2497,7 +2497,7 @@ describe UsersController do
             expect(user.user_avatar.reload.custom_upload_id).to eq(avatar1.id)
           end
 
-          it 'can succesfully select an avatar using a cooked URL' do
+          it 'can successfully select an avatar using a cooked URL' do
             events = DiscourseEvent.track_events do
               put "/u/#{user.username}/preferences/avatar/select.json", params: { url: UrlHelper.cook_url(avatar1.url) }
             end
diff --git a/spec/serializers/post_revision_serializer_spec.rb b/spec/serializers/post_revision_serializer_spec.rb
index 64013180fca..ea690df829f 100644
--- a/spec/serializers/post_revision_serializer_spec.rb
+++ b/spec/serializers/post_revision_serializer_spec.rb
@@ -47,7 +47,7 @@ describe PostRevisionSerializer do
       expect(json[:tags_changes][:current]).to eq([public_tag2.name])
     end
 
-    it 'does not show tag modificiatons if changes are not visible to the user' do
+    it 'does not show tag modifications if changes are not visible to the user' do
       json = PostRevisionSerializer.new(post_revision2, scope: Guardian.new(Fabricate(:user)), root: false).as_json
       expect(json[:tags_changes]).to_not be_present
     end
diff --git a/spec/serializers/topic_view_serializer_spec.rb b/spec/serializers/topic_view_serializer_spec.rb
index b9a9d03e250..c7515a8fd64 100644
--- a/spec/serializers/topic_view_serializer_spec.rb
+++ b/spec/serializers/topic_view_serializer_spec.rb
@@ -467,7 +467,7 @@ describe TopicViewSerializer do
       end
     end
 
-    context 'Wwhen the slow mode is enabled' do
+    context 'When the slow mode is enabled' do
       before { topic.update!(slow_mode_seconds: 1000) }
 
       it 'returns nil if no user is given' do
diff --git a/spec/services/badge_granter_spec.rb b/spec/services/badge_granter_spec.rb
index 1679f067223..fea28b4b19b 100644
--- a/spec/services/badge_granter_spec.rb
+++ b/spec/services/badge_granter_spec.rb
@@ -391,7 +391,7 @@ describe BadgeGranter do
       expect(UserBadge.where(user_id: user.id, badge_id: Badge::Autobiographer).count).to eq(1)
     end
 
-    it "grants read guidlines" do
+    it "grants read guidelines" do
       user.user_stat.read_faq = Time.now
       user.user_stat.save
 
diff --git a/spec/services/destroy_task_spec.rb b/spec/services/destroy_task_spec.rb
index 5d41a73d0cc..476cbff4200 100644
--- a/spec/services/destroy_task_spec.rb
+++ b/spec/services/destroy_task_spec.rb
@@ -106,7 +106,7 @@ describe DestroyTask do
       destroy_task = DestroyTask.new(StringIO.new)
       destroy_task.destroy_users
       expect(User.where(admin: false).count).to eq 0
-      # admin does not get detroyed
+      # admin does not get destroyed
       expect(User.count).to eq before_count + 1
     end
   end
diff --git a/spec/services/inline_uploads_spec.rb b/spec/services/inline_uploads_spec.rb
index c46b6d7b69a..03c4fc56801 100644
--- a/spec/services/inline_uploads_spec.rb
+++ b/spec/services/inline_uploads_spec.rb
@@ -681,13 +681,13 @@ RSpec.describe InlineUploads do
 
       it "should correct markdown references" do
         md = <<~MD
-        This is a [some reference] somethign
+        This is a [some reference] something
 
         [some reference]: https:#{upload.url}
         MD
 
         expect(InlineUploads.process(md)).to eq(<<~MD)
-        This is a [some reference] somethign
+        This is a [some reference] something
 
         [some reference]: #{Discourse.base_url}#{upload.short_path}
         MD
diff --git a/spec/services/post_action_notifier_spec.rb b/spec/services/post_action_notifier_spec.rb
index ed63971a3b0..f1bf3e08de9 100644
--- a/spec/services/post_action_notifier_spec.rb
+++ b/spec/services/post_action_notifier_spec.rb
@@ -145,7 +145,7 @@ describe PostActionNotifier do
         }.to change(post.user.notifications, :count).by(1)
       end
 
-      it 'does not notifiy a user of the revision made by the system user' do
+      it 'does not notify a user of the revision made by the system user' do
         expect {
           post.revise(Discourse.system_user, raw: "world is the new body of the message")
         }.not_to change(post.user.notifications, :count)
diff --git a/spec/services/post_alerter_spec.rb b/spec/services/post_alerter_spec.rb
index 86ca47e0187..a07ff600540 100644
--- a/spec/services/post_alerter_spec.rb
+++ b/spec/services/post_alerter_spec.rb
@@ -442,7 +442,7 @@ describe PostAlerter do
         expect(n.data_hash["original_username"]).to eq(admin.username)
     end
 
-    it "doesn't notify the last post editor if they mention themself" do
+    it "doesn't notify the last post editor if they mention themselves" do
       post = create_post_with_alerts(user: user, raw: 'Post without a mention.')
       expect {
         post.revise(evil_trout, raw: "O hai, @eviltrout!")
@@ -1215,7 +1215,7 @@ describe PostAlerter do
         post.topic.allowed_users << staged
       end
 
-      it "only notifes staff watching added tag" do
+      it "only notifies staff watching added tag" do
         expect(PostRevisor.new(post).revise!(Fabricate(:admin), tags: [other_tag.name])).to be true
         expect(Notification.where(user_id: staged.id).count).to eq(0)
         expect(PostRevisor.new(post).revise!(Fabricate(:admin), tags: [other_tag2.name])).to be true
diff --git a/spec/services/search_indexer_spec.rb b/spec/services/search_indexer_spec.rb
index 4fe3f1d9975..c890c430aa4 100644
--- a/spec/services/search_indexer_spec.rb
+++ b/spec/services/search_indexer_spec.rb
@@ -202,7 +202,7 @@ describe SearchIndexer do
 
       post = Fabricate(:post, topic: topic, raw: <<~RAW)
       a https://abc.com?bob=1, http://efg.com.au?bill=1 b hij.net/xyz=1
-      www.klm.net/?IGNORE=1 <a href="http://abc.de.nop.co.uk?IGNORE=1&ingore2=2">test</a>
+      www.klm.net/?IGNORE=1 <a href="http://abc.de.nop.co.uk?IGNORE=1&ignore2=2">test</a>
       RAW
 
       post.rebake!
diff --git a/spec/services/site_settings_spec.rb b/spec/services/site_settings_spec.rb
index 5cc546bcbc8..962c781bb98 100644
--- a/spec/services/site_settings_spec.rb
+++ b/spec/services/site_settings_spec.rb
@@ -47,7 +47,7 @@ describe SiteSettingsTask do
       expect(counts[:not_found]).to eq 1
     end
 
-    it "will log that an error has occured" do
+    it "will log that an error has occurred" do
       yml = "min_password_length: 0"
       log, counts = SiteSettingsTask.import(yml)
       expect(log[0]).to eq "ERROR: min_password_length: Value must be between 8 and 500."
diff --git a/spec/services/user_anonymizer_spec.rb b/spec/services/user_anonymizer_spec.rb
index d8ec0597ea7..13079905455 100644
--- a/spec/services/user_anonymizer_spec.rb
+++ b/spec/services/user_anonymizer_spec.rb
@@ -198,7 +198,7 @@ describe UserAnonymizer do
       expect(history.details).not_to match(orig_username)
     end
 
-    it "removes external auth assocations" do
+    it "removes external auth associations" do
       user.user_associated_accounts = [UserAssociatedAccount.create(user_id: user.id, provider_uid: "example", provider_name: "facebook")]
       user.single_sign_on_record = SingleSignOnRecord.create(user_id: user.id, external_id: "example", last_payload: "looks good")
       user.oauth2_user_infos = [Oauth2UserInfo.create(user_id: user.id, uid: "example", provider: "example")]
diff --git a/spec/services/user_authenticator_spec.rb b/spec/services/user_authenticator_spec.rb
index 8f2b86b686c..718f779afb9 100644
--- a/spec/services/user_authenticator_spec.rb
+++ b/spec/services/user_authenticator_spec.rb
@@ -44,7 +44,7 @@ describe UserAuthenticator do
   context "#finish" do
     fab!(:group) { Fabricate(:group, automatic_membership_email_domains: "discourse.org") }
 
-    it "confirms email and adds the user to appropraite groups based on email" do
+    it "confirms email and adds the user to appropriate groups based on email" do
       user = Fabricate(:user, email: "user53@discourse.org")
       expect(group.usernames).not_to include(user.username)
 
diff --git a/spec/services/user_merger_spec.rb b/spec/services/user_merger_spec.rb
index ef77a76a5c1..55996ac52f0 100644
--- a/spec/services/user_merger_spec.rb
+++ b/spec/services/user_merger_spec.rb
@@ -837,7 +837,7 @@ describe UserMerger do
     expect(UserEmail.where(user_id: source_user.id).count).to eq(0)
   end
 
-  it "skips merging email adresses when a secondary email address exists" do
+  it "skips merging email addresses when a secondary email address exists" do
     merge_users!(source_user, target_user)
 
     alice2 = Fabricate(:user, username: 'alice2', email: 'alice@foo.com')
diff --git a/spec/services/user_notification_schedule_processor_spec.rb b/spec/services/user_notification_schedule_processor_spec.rb
index 152667df941..e835927af47 100644
--- a/spec/services/user_notification_schedule_processor_spec.rb
+++ b/spec/services/user_notification_schedule_processor_spec.rb
@@ -28,7 +28,7 @@ describe UserNotificationScheduleProcessor do
           UserNotificationScheduleProcessor.create_do_not_disturb_timings_for(standard_schedule)
 
           # The default schedule is 8am - 5pm.
-          # Expext DND timings to fill gaps before/after those times for 3 days.
+          # Expect DND timings to fill gaps before/after those times for 3 days.
           dnd_timings = user.do_not_disturb_timings
           offset = timezone_info[:offset]
           expect(dnd_timings[0].starts_at).to eq_time(Time.new(2020, 1, 4, 0, 0, 0, offset))
diff --git a/spec/services/user_updater_spec.rb b/spec/services/user_updater_spec.rb
index ddc9371d662..b9af1c7a95a 100644
--- a/spec/services/user_updater_spec.rb
+++ b/spec/services/user_updater_spec.rb
@@ -173,7 +173,7 @@ describe UserUpdater do
       expect(user.user_option.mailing_list_mode).to eq true
     end
 
-    it "filters theme_ids blank values before updating perferences" do
+    it "filters theme_ids blank values before updating preferences" do
       user = Fabricate(:user)
       user.user_option.update!(theme_ids: [1])
       updater = UserUpdater.new(acting_user, user)
diff --git a/spec/services/word_watcher_spec.rb b/spec/services/word_watcher_spec.rb
index 5cf70b65839..9c76c64aab8 100644
--- a/spec/services/word_watcher_spec.rb
+++ b/spec/services/word_watcher_spec.rb
@@ -4,7 +4,7 @@ require 'rails_helper'
 
 describe WordWatcher do
 
-  let(:raw) { "Do you like liquorice?\n\nI really like them. One could even say that I am *addicted* to liquorice. Anf if\nyou can mix it up with some anise, then I'm in heaven ;)" }
+  let(:raw) { "Do you like liquorice?\n\nI really like them. One could even say that I am *addicted* to liquorice. And if\nyou can mix it up with some anise, then I'm in heaven ;)" }
 
   after do
     Discourse.redis.flushdb
diff --git a/spec/support/shared_examples_for_stats_cacheable.rb b/spec/support/shared_examples_for_stats_cacheable.rb
index a2d77e47bc9..83b5fdae7dd 100644
--- a/spec/support/shared_examples_for_stats_cacheable.rb
+++ b/spec/support/shared_examples_for_stats_cacheable.rb
@@ -1,6 +1,6 @@
 # frozen_string_literal: true
 
-shared_examples_for 'stats cachable' do
+shared_examples_for 'stats cacheable' do
   describe 'fetch_cached_stats' do
     after do
       Discourse.redis.del(described_class.stats_cache_key)
diff --git a/test/run-qunit.js b/test/run-qunit.js
index 9737efc35aa..67dbc8157bf 100644
--- a/test/run-qunit.js
+++ b/test/run-qunit.js
@@ -168,7 +168,7 @@ runAllTests().catch((e) => {
 });
 
 // The following functions are converted to strings
-// And then sent to chrome to be evalaluated
+// And then sent to chrome to be evaluated
 function logQUnit() {
   let testErrors = [];
   let assertionErrors = [];
diff --git a/test/smoke_test.js b/test/smoke_test.js
index abd1a4589b8..979d05d883f 100644
--- a/test/smoke_test.js
+++ b/test/smoke_test.js
@@ -16,7 +16,7 @@ const path = require("path");
 
 (async () => {
   const browser = await puppeteer.launch({
-    // when debugging localy setting the SHOW_BROWSER env variable can be very helpful
+    // when debugging locally setting the SHOW_BROWSER env variable can be very helpful
     headless: process.env.SHOW_BROWSER === undefined,
     args: ["--disable-local-storage", "--no-sandbox"]
   });