1 2 3 4<!DOCTYPE html> 5<html lang="en" dir="ltr"> 6<head> 7 <meta charset="UTF-8"> 8 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 9 <title>Grammar Learning Paths A1âB2 | GrammarMama</title> 10 <meta name="description" content="Free, structured grammar learning paths by CEFR level. Browse every grammar topic you need from A1 to B2 â clear explanations and examples, no sign-up required."> 11 <meta property="og:type" content="website"> 12 <meta property="og:url" content="https://grammarmama.com/learn/"> 13 <meta property="og:title" content="Grammar Learning Paths A1âB2 | GrammarMama"> 14 <meta property="og:description" content="Free, structured grammar learning paths by CEFR level. Browse every grammar topic you need from A1 to B2 â clear explanations and examples, no sign-up required."> 15 <link rel="canonical" href="https://grammarmama.com/learn/"> 16 17 <link rel="alternate" hreflang="en" href="https://grammarmama.com/learn/"> 18 19 <link rel="alternate" hreflang="de" href="https://grammarmama.com/de/learn/"> 20 21 <link rel="alternate" hreflang="ru" href="https://grammarmama.com/ru/learn/"> 22 23 <link rel="alternate" hreflang="fr" href="https://grammarmama.com/fr/learn/"> 24 25 <link rel="alternate" hreflang="es" href="https://grammarmama.com/es/learn/"> 26 27 <link rel="alternate" hreflang="it" href="https://grammarmama.com/it/learn/"> 28 29 <link rel="alternate" hreflang="pl" href="https://grammarmama.com/pl/learn/"> 30 31 <link rel="alternate" hreflang="zh" href="https://grammarmama.com/zh/learn/"> 32 33 <link rel="alternate" hreflang="pt" href="https://grammarmama.com/pt/learn/"> 34 35 <link rel="alternate" hreflang="ja" href="https://grammarmama.com/ja/learn/"> 36 37 <link rel="alternate" hreflang="x-default" href="https://grammarmama.com/learn/"> 38 <link rel="icon" href="/favicon.ico"> 39 <link rel="stylesheet" href="/styles.css"> 40</head> 41<body> 42 43 44<header class="site-header"> 45 <nav class="site-nav"> 46 <a href="/" class="site-nav-link">Check</a> 47 <a href="/learn/" class="site-nav-link">Learn</a> 48 <a href="/practice/" class="site-nav-link">Practice</a> 49 <a href="/vocabulary/" class="site-nav-link">Vocabulary</a> 50 <a href="/profile/" class="site-nav-link">Profile</a> 51 </nav> 52</header> 53 54 <main class="content-page"> 55 56 <div class="kb-layout"> 57 58 59<aside class="kb-aside"> 60 <img src="/images/mascot.webp" alt="GrammarMama mascot" class="mascot-img" width="140" height="140"> 61 <nav class="lang-sidebar" aria-label="Your native language:"> 62 <div class="lang-sidebar-label">Your native language:</div> 63 <ul class="lang-pill-list"> 64 65 66 67 68 <li> 69 70 <span class="lang-pill active">English</span> 71 72 </li> 73 74 75 76 77 <li> 78 79 <a class="lang-pill" href="/de/learn/" hreflang="de">Deutsch</a> 80 81 </li> 82 83 84 85 86 <li> 87 88 <a class="lang-pill" href="/ru/learn/" hreflang="ru">Ð ÑÑÑкий</a> 89 90 </li> 91 92 93 94 95 <li> 96 97 <a class="lang-pill" href="/fr/learn/" hreflang="fr">Français</a> 98 99 </li> 100 101 102 103 104 <li> 105 106 <a class="lang-pill" href="/es/learn/" hreflang="es">Español</a> 107 108 </li> 109 110 111 112 113 <li> 114 115 <a class="lang-pill" href="/it/learn/" hreflang="it">Italiano</a> 116 117 </li> 118 119 120 121 122 <li> 123 124 <a class="lang-pill" href="/pl/learn/" hreflang="pl">Polski</a> 125 126 </li> 127 128 129 130 131 <li> 132 133 <a class="lang-pill" href="/zh/learn/" hreflang="zh">䏿</a> 134 135 </li> 136 137 138 139 140 <li> 141 142 <a class="lang-pill" href="/pt/learn/" hreflang="pt">Português</a> 143 144 </li> 145 146 147 148 149 <li> 150 151 <a class="lang-pill" href="/ja/learn/" hreflang="ja">æ¥æ¬èª</a> 152 153 </li> 154 155 </ul> 156 </nav> 157</aside> 158 159 <div class="content-container"> 160 <div class="blog-post-nav"> 161 <a href="/" class="blog-post-cta">
161â Home</a> 162 </div> 163 <h1>Grammar Learning Paths</h1> 164 <p class="post-date">Every grammar topic you need, organised by language and level â from your first words to confident, complex sentences.</p> 165 166 <h2>Which language are you learning?</h2> 167 <div class="kb-lang-grid"> 168 169 170 171 <a class="kb-lang-card" href="/learn/english/"> 172 <span class="kb-lang-name">English</span> 173 <span class="kb-lang-levels">A1âC2</span> 174 </a> 175 176 177 178 179 <a class="kb-lang-card" href="/learn/german/"> 180 <span class="kb-lang-name">German</span> 181 <span class="kb-lang-levels">A1âC2</span> 182 </a> 183 184 185 186 187 <a class="kb-lang-card" href="/learn/russian/"> 188 <span class="kb-lang-name">Russian</span> 189 <span class="kb-lang-levels">A1âC2</span> 190 </a> 191 192 193 194 195 <a class="kb-lang-card" href="/learn/french/"> 196 <span class="kb-lang-name">French</span> 197 <span class="kb-lang-levels">A1âC2</span> 198 </a> 199 200 201 202 203 <a class="kb-lang-card" href="/learn/spanish/"> 204 <span class="kb-lang-name">Spanish</span> 205 <span class="kb-lang-levels">A1âC2</span> 206 </a> 207 208 209 210 211 <a class="kb-lang-card" href="/learn/italian/"> 212 <span class="kb-lang-name">Italiano</span> 213 <span class="kb-lang-levels">A1âC2</span> 214 </a> 215 216 217 218 219 <a class="kb-lang-card" href="/learn/norwegian/"> 220 <span class="kb-lang-name">Norwegian</span> 221 <span class="kb-lang-levels">A1âC2</span> 222 </a> 223 224 225 226 227 <span class="kb-lang-card kb-lang-card--soon"> 228 <span class="kb-lang-name">Polski</span> 229 <span class="kb-lang-levels">Coming soon</span> 230 </span> 231 232 233 234 235 <span class="kb-lang-card kb-lang-card--soon"> 236 <span class="kb-lang-name">䏿</span> 237 <span class="kb-lang-levels">Coming soon</span> 238 </span> 239 240 241 242 243 <span class="kb-lang-card kb-lang-card--soon"> 244 <span class="kb-lang-name">æ¥æ¬èª</span> 245 <span class="kb-lang-levels">Coming soon</span> 246 </span> 247 248 249 250 251 <span class="kb-lang-card kb-lang-card--soon"> 252 <span class="kb-lang-name">Português</span> 253 <span class="kb-lang-levels">Coming soon</span> 254 </span> 255 256 257 </div> 258 </div> 259 </div> 260 </main> 261 262 263 264 265
266<script> 267(function () { 268 var REDIRECTABLE = ['/', '/practice/', '/vocabulary/', '/profile/']; 269 if (REDIRECTABLE.indexOf(window.location.pathname) === -1) return; 270 // Same key/TTL as profile.njk's _TELEGRAM_INTENT_KEY â duplicated here (not shared) because 271 // this script and profile.njk's are two separate template scopes. 272 function _hasTelegramConnectIntent() { 273 try { 274 var t = parseInt(localStorage.getItem('gm_telegram_connect_intent'), 10); 275 return !!t && (Date.now() - t) < 30 * 60 * 1000; 276 } catch (e) { return false; } 277 } 278 window.addEventListener('load', function () { 279 if (!window.Clerk) return; 280 window.Clerk.load().then(function () { 281 if (!window.Clerk.user || !window.Clerk.session) return; 282 window.Clerk.session.getToken({ template: 'grammar-mama-template' }) 283 .then(function (token) { 284 if (!token) return Promise.resolve(null); 285 return fetch('/api/user', { headers: { Authorization: 'Bearer ' + token } }); 286 }) 287 .then(function (resp) { 288 if (!resp || !resp.ok) return Promise.resolve(null); 289 return resp.json(); 290 }) 291 .then(function (user) { 292 if (!user) return; 293 // Clerk's post-login redirect does not reliably land back on /profile (it can land 294 // on this page's own path instead, e.g. home) â if there's a pending Telegram-connect 295 // intent (see profile.njk), finish the trip there instead of the normal locale redirect. 296 // profile.njk itself already handles the rest once it's the page loaded. 297 if (_hasTelegramConnectIntent() && !user.telegramLinked && window.location.pathname.indexOf('/profile/') === -1) { 298 var langPrefix = user.nativeLanguage && user.nativeLanguage !== 'en' ? '/' + user.nativeLanguage : ''; 299 window.location.replace(langPrefix + '/profile/?connectTelegram=1'); 300 return; 301 } 302 if (!user.nativeLanguage || user.nativeLanguage === 'en') return; 303 window.location.replace('/' + user.nativeLanguage + window.location.pathname); 304 }) 305 .catch(function () {}); 306 }); 307 }); 308})(); 309</script>
309 310 311 <footer> 312 <a href="/">Home</a> 313 <a href="/learn/">Learn</a> 314 <a href="/blog.html">Blog</a> 315 <a href="/pricing.html">Pricing</a> 316 <a href="/terms.html">T&C</a> 317 <a href="/privacy.html">Privacy</a> 318 <a href="/refund.html">Refund Policy</a> 319 <a href="/#contact">Contact</a> 320 <a href="/#feedback">Feedback</a> 321 <a href="#" id="gmCookieSettingsLink">Cookie settings</a> 322 </footer> 323 324 325 <div class="cookie-banner" id="gmCookieBanner" role="dialog" aria-live="polite" aria-label="Cookie settings" hidden> 326 <div class="cookie-banner__box"> 327 <p>We use optional analytics cookies to see how visitors use GrammarMama, so we can keep improving it. Essential cookies (like keeping you signed in) are always on. <a href="/privacy.html">Privacy policy</a></p> 328 <div class="cookie-banner__actions"> 329 <button type="button" class="cookie-banner__reject" id="gmCookieReject">Decline</button> 330 <button type="button" class="cookie-banner__accept" id="gmCookieAccept">Accept</button> 331 </div> 332 </div> 333 </div> 334
334<script> 335 (function () { 336 var KEY = 'gm_cookie_consent'; 337 var banner = document.getElementById('gmCookieBanner'); 338 var acceptBtn = document.getElementById('gmCookieAccept'); 339 var rejectBtn = document.getElementById('gmCookieReject'); 340 var settingsLink = document.getElementById('gmCookieSettingsLink'); 341 342 function getConsent() { 343 try { return localStorage.getItem(KEY); } catch (e) { return null; } 344 } 345 function setConsent(v) { 346 try { localStorage.setItem(KEY, v); } catch (e) {} 347 } 348 349 window.GM_CONSENT = { granted: getConsent() === 'accepted', onChange: null }; 350 351 function show() { if (banner) banner.hidden = false; } 352 function hide() { if (banner) banner.hidden = true; } 353 354 function decide(value) { 355 setConsent(value); 356 window.GM_CONSENT.granted = (value === 'accepted'); 357 hide(); 358 if (typeof window.GM_CONSENT.onChange === 'function') { 359 window.GM_CONSENT.onChange(window.GM_CONSENT.granted); 360 } 361 } 362 363 if (acceptBtn) acceptBtn.addEventListener('click', function () { decide('accepted'); }); 364 if (rejectBtn) rejectBtn.addEventListener('click', function () { decide('rejected'); }); 365 if (settingsLink) { 366 settingsLink.addEventListener('click', function (e) { e.preventDefault(); show(); }); 367 } 368 369 if (getConsent() === null) show(); 370 371 // Funnel event helper. Fans out one call to both GA4 (gtag) and Clarity. 372 // No-op until an analytics script is actually loaded (i.e. consent granted), 373 // so callers everywhere can fire events unconditionally. props become GA4 374 // event params and Clarity custom tags. 375 window.GM_TRACK = function (name, props) { 376 props = props || {}; 377 try { 378 if (typeof window.gtag === 'function') window.gtag('event', name, props); 379 if (typeof window.clarity === 'function') { 380 window.clarity('event', name); 381 for (var k in props) { 382 if (Object.prototype.hasOwnProperty.call(props, k) && props[k] != null) { 383 window.clarity('set', k, String(props[k])); 384 } 385 } 386 } 387 } catch (e) {} 388 }; 389 390 // Signup-completion detector. A signup CTA sets localStorage 'gm_signup_intent' 391 // before Clerk redirects away; on the page it lands back on, wait for Clerk to 392 // report a signed-in user, then fire one 'sign_up' event and clear the flag. 393 (function () { 394 var FLAG = 'gm_signup_intent'; 395 var pending = null; 396 try { pending = localStorage.getItem(FLAG); } catch (e) {} 397 if (!pending) return; 398 var tries = 0; 399 var iv = setInterval(function () { 400 tries += 1; 401 if (window.Clerk && window.Clerk.user) { 402 clearInterval(iv); 403 try { localStorage.removeItem(FLAG); } catch (e) {} 404 if (window.GM_TRACK) window.GM_TRACK('sign_up', { source: pending }); 405 } else if (tries > 40) { 406 clearInterval(iv); 407 } 408 }, 500); 409 })(); 410 })(); 411 </script>
411 412 413 414 415
415<script> 416 (function () { 417 var GA_ID = "G-KMYM08QRY7"; 418 var CLARITY_ID = "yditf2dtk5"; 419 var _loaded = false; 420 421 function loadGa() { 422 if (!GA_ID) return; 423 var s = document.createElement('script'); 424 s.async = true; 425 s.src = 'https://www.googletagmanager.com/gtag/js?id=' + GA_ID; 426 document.head.appendChild(s); 427 window.dataLayer = window.dataLayer || []; 428 window.gtag = function () { window.dataLayer.push(arguments); }; 429 window.gtag('js', new Date()); 430 window.gtag('config', GA_ID); 431 } 432 433 function loadClarity() { 434 if (!CLARITY_ID) return; 435 (function (c, l, a, r, i, t, y) { 436 c[a] = c[a] || function () { (c[a].q = c[a].q || []).push(arguments); }; 437 t = l.createElement(r); t.async = 1; t.src = 'https://www.clarity.ms/tag/' + i; 438 y = l.getElementsByTagName(r)[0]; y.parentNode.insertBefore(t, y); 439 })(window, document, 'clarity', 'script', CLARITY_ID); 440 } 441 442 function setContext() { 443 var loc = document.documentElement.lang || 'en'; 444 var pt = window.GM_PAGE_TYPE || ''; 445 var authState = (window.Clerk && window.Clerk.user) ? 'signedIn' : 'anonymous'; 446 try { 447 if (typeof window.gtag === 'function') { 448 window.gtag('set', 'user_properties', { locale: loc, page_type: pt, auth_state: authState }); 449 } 450 if (typeof window.clarity === 'function') { 451 window.clarity('set', 'locale', loc); 452 if (pt) window.clarity('set', 'pageType', pt); 453 window.clarity('set', 'authState', authState); 454 } 455 } catch (e) {} 456 } 457 458 function loadAll() { 459 if (_loaded) return; 460 _loaded = true; 461 loadGa(); 462 loadClarity(); 463 setContext(); 464 // GM_PAGE_TYPE / Clerk.user are often set by scripts that run after this one. 465 window.setTimeout(setContext, 1500); 466 } 467 468 if (window.GM_CONSENT && window.GM_CONSENT.granted) loadAll(); 469 if (window.GM_CONSENT) { 470 window.GM_CONSENT.onChange = function (granted) { if (granted) loadAll(); }; 471 } 472 })(); 473 </script>
473 474 475 476</body> 477</html> 478
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.