JavaScript
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax and Types
-
Section 3: Strings and Numbers in Depth
-
Section 4: Control Flow
-
Section 5: Functions
-
Section 6: Objects and Arrays
-
Section 7: Maps, Sets, and Symbols
-
Section 8: Asynchronous JavaScript
-
Section 9: Object-Oriented and Prototypes
-
Section 10: The DOM
-
Section 11: Browser APIs
-
Section 12: Modern JavaScript (ES2015-ES2025)
-
Section 13: Functional Programming Patterns
-
Section 14: Error Handling and Debugging
-
Section 15: Testing
-
Section 16: Accessibility for JavaScript Developers
-
Section 17: Internationalization and Localization
-
Section 18: Performance
-
Section 19: Node.js Fundamentals
-
Section 20: Regular Expressions
-
Section 21: Design Patterns in JavaScript
-
Section 22: Security Basics
-
Section 23: Data Structures and Algorithms in JavaScript
-
Section 24: Practical Projects
-
Section 25: More Advanced Async Patterns
-
Section 26: More Object and Class Practice
-
Section 27: Working with Dates and Internationalization
-
Section 28: Web Components
-
Section 29: More DOM and Browser Practice
-
Section 30: Build Tooling for Vanilla JavaScript
-
Section 31: More Practice Projects
-
Section 32: Interview and Algorithm Practice
-
Section 33: Error Objects (MDN Reference)
-
Section 34: TypedArrays and Binary Data
-
Section 35: Reflection and Metaprogramming (MDN Reference)
-
Section 36: More Global Functions (MDN Reference)
133: Using the Intl API for Pluralization
I can't tell you how many times I've walked into a code review and seen a line like ${count} ${count === 1 ? 'message' : 'messages'}. In the moment, it feels efficient. It's one line of code, it's readable, and for those of us working primarily in English, it's technically correct. But if your app ever needs to scale beyond English-speaking markets, this pattern becomes a liability.
The temptation of the ternary operator
When we think about plurals in English, we think in binaries: it's either singular or it isn't. This leads us to write logic that assumes every language on earth follows this same rule. Let's look at a typical notification counter implementation:
const getMessageText = (count) => {
return `${count} ${count === 1 ? 'unread message' : 'unread messages'}`;
};
console.log(getMessageText(1)); // "1 unread message"
console.log(getMessageText(2)); // "2 unread messages"
console.log(getMessageText(0)); // "0 unread messages"
This is what I call "naive pluralization." It works for English, and it might even work for a few other languages, but it's fundamentally based on a false premise about how human language works.
When the binary assumption fails
The problem is that "plural" isn't a toggle switch in most of the world. Take Polish, for example. They have different noun forms depending on whether the number ends in 2, 3, or 4, versus numbers ending in 5 through 21. Arabic is even more complex, with distinct categories for zero, one, two, numbers from 3 to 10, and numbers from 11 to 99. If you try to force these languages into a count === 1 ternary, your UI will look broken or, worse, grammatically illiterate to your users.
I've seen teams realize this far too late in the development cycle, forcing them to go back and hunt down every single ternary plural across the entire codebase. It's a nightmare to refactor once the app is large.
Letting the browser handle the linguistic heavy lifting
This is where Intl.PluralRules comes in. Instead of you trying to memorize the grammatical rules of 100 different languages, you ask the browser to categorize the number for you. The API doesn't return the final string; instead, it returns a "category" (like 'one', 'two', 'few', 'many', or 'other') based on the locale provided.
const pr = new Intl.PluralRules('en-US');
console.log(pr.select(1)); // "one"
console.log(pr.select(2)); // "other"
console.log(pr.select(0)); // "other"
const prArabic = new Intl.PluralRules('ar');
console.log(prArabic.select(0)); // "zero"
console.log(prArabic.select(1)); // "one"
console.log(prArabic.select(2)); // "two"
console.log(prArabic.select(3)); // "few"
console.log(prArabic.select(11)); // "many"
By using select(), you're decoupling the logic of pluralization (which is handled by the browser) from the content of the pluralization (which is handled by your translation files).
Adding a bit of mapping overhead for global correctness
The trade-off here is that you can't just write a one-liner anymore. You need a mapping object that provides the correct string for each category. It's a bit more boilerplate, but it's the only way to be truly internationalized.
Here is how I would actually implement that notification counter in a production environment:
const messages = {
'en-US': {
one: 'unread message',
other: 'unread messages',
},
'ar': {
zero: 'رسالة غير مقروءة',
one: 'رسالة واحدة غير مقروءة',
two: 'رسالتان غير مقروءتين',
few: 'رسائل غير مقروءة',
many: 'رسائل غير مقروءة',
other: 'رسائل غير مقروءة',
}
};
function formatNotification(count, locale) {
const pr = new Intl.PluralRules(locale);
const category = pr.select(count);
const term = messages[locale][category] || messages[locale]['other'];
return `${count} ${term}`;
}
console.log(formatNotification(2, 'en-US')); // "2 unread messages"
console.log(formatNotification(2, 'ar')); // "2 رسالتان غير مقروءتين"
You'll notice I added a fallback to 'other'. This is important because 'other' is the only category guaranteed to exist across all locales. If your translation file is missing a specific category, falling back to 'other' ensures the app doesn't crash and still provides a reasonably understandable message.
📋 Practical Task
Implementing a Multi-Locale File Upload Counter
You are building a file upload component that needs to support both English (en-US) and Russian (ru). Russian pluralization is notoriously tricky: it uses one, few, and many.
Your Task: Create a function called formatFileCount(count, locale).
- Use
Intl.PluralRulesto determine the correct plural category. - Create a translation map for
en-US(usingoneandother) andru(usingone,few, andmany). - The Russian terms should be:
one: "файл"few: "файла"many: "файлов"
- Ensure the function returns a string combining the number and the correct term (e.g.,
"1 файл"or"5 файлов"). - Include a fallback to
'other'for the English locale to prevent errors.
There are no comments for now.