javascript
exercises
exercises.js⚡javascript
/**
* 9.3 Internationalization (Intl) - Exercises
*/
/**
* Exercise 1: Currency Formatter
* Create a function that formats amounts in different currencies
*/
function formatCurrency(amount, currencyCode, locale) {
// TODO: Format the amount as currency
// Use appropriate locale for the currency if locale not provided
// Return formatted string
}
// Test:
// console.log(formatCurrency(1234.56, 'USD')); // $1,234.56
// console.log(formatCurrency(1234.56, 'EUR', 'de-DE')); // 1.234,56 €
// console.log(formatCurrency(1234.56, 'JPY')); // ¥1,235
/**
* Exercise 2: Multi-locale Number Formatter
* Create a number formatter with multiple output formats
*/
function createNumberFormatter(locale) {
// TODO: Return object with methods:
// - format(n): basic number formatting
// - percent(n): percentage formatting
// - compact(n): compact notation
// - scientific(n): scientific notation
// - currency(n, code): currency formatting
}
// Test:
// const fmt = createNumberFormatter('en-US');
// console.log(fmt.format(1234567)); // "1,234,567"
// console.log(fmt.percent(0.75)); // "75%"
// console.log(fmt.compact(1234567)); // "1.2M"
/**
* Exercise 3: Smart Date Formatter
* Format dates based on how recent they are
*/
function smartFormatDate(date, locale = 'en-US') {
// TODO: Format date intelligently:
// - Same day: time only (2:30 PM)
// - Yesterday: "Yesterday at 2:30 PM"
// - This week: "Tuesday at 2:30 PM"
// - This year: "Mar 15 at 2:30 PM"
// - Older: "Mar 15, 2023"
}
// Test:
// console.log(smartFormatDate(new Date()));
// console.log(smartFormatDate(new Date(Date.now() - 86400000)));
/**
* Exercise 4: Relative Time Calculator
* Calculate and format relative time differences
*/
function relativeTime(date, baseDate = new Date(), locale = 'en') {
// TODO: Calculate difference and return relative time string
// Handle: seconds, minutes, hours, days, weeks, months, years
// Use numeric: 'auto' for natural language
}
// Test:
// console.log(relativeTime(new Date(Date.now() - 60000))); // "1 minute ago"
// console.log(relativeTime(new Date(Date.now() + 86400000))); // "tomorrow"
/**
* Exercise 5: Duration Formatter
* Format durations in a locale-aware way
*/
function formatDuration(seconds, locale = 'en', style = 'long') {
// TODO: Format duration like "2 hours, 30 minutes, and 15 seconds"
// Use Intl.ListFormat and Intl.NumberFormat with units
}
// Test:
// console.log(formatDuration(9015)); // "2 hours, 30 minutes, and 15 seconds"
// console.log(formatDuration(90, 'en', 'narrow')); // "1 min 30 sec"
/**
* Exercise 6: Pluralization System
* Create a comprehensive pluralization system
*/
class Pluralizer {
// TODO: Implement pluralization for different locales
// constructor(locale)
// addRule(key, forms): Add pluralization forms
// forms = { zero, one, two, few, many, other }
// format(key, count): Return pluralized string
// e.g., format('item', 5) => "5 items"
}
// Test:
// const pl = new Pluralizer('en');
// pl.addRule('apple', { one: '# apple', other: '# apples' });
// console.log(pl.format('apple', 1)); // "1 apple"
// console.log(pl.format('apple', 5)); // "5 apples"
/**
* Exercise 7: Locale-Aware Sorting
* Create a sorting utility with locale support
*/
function createSorter(locale, options = {}) {
// TODO: Return a function that sorts arrays
// Support options: numeric, caseFirst, sensitivity
// Handle arrays of strings or objects with a key
}
// Test:
// const sort = createSorter('en', { numeric: true });
// console.log(sort(['item10', 'item2', 'item1']));
// // ['item1', 'item2', 'item10']
/**
* Exercise 8: Display Names Utility
* Create a utility for displaying localized names
*/
class LocaleDisplayNames {
// TODO: Implement
// constructor(displayLocale)
// region(code): Get region name
// language(code): Get language name
// currency(code): Get currency name
// script(code): Get script name
// all(code): Try to determine type and return name
}
// Test:
// const names = new LocaleDisplayNames('en');
// console.log(names.region('DE')); // "Germany"
// console.log(names.language('de')); // "German"
// console.log(names.currency('EUR')); // "Euro"
/**
* Exercise 9: Invoice Formatter
* Create a locale-aware invoice formatter
*/
class InvoiceFormatter {
// TODO: Create invoice formatter
// constructor(locale, currency)
// formatLineItem(item): { description, quantity, unitPrice, total }
// formatSubtotal(amount)
// formatTax(amount, rate)
// formatTotal(amount)
// formatDate(date)
// formatInvoiceNumber(number)
}
// Test:
// const inv = new InvoiceFormatter('de-DE', 'EUR');
// console.log(inv.formatLineItem({
// description: 'Widget',
// quantity: 10,
// unitPrice: 99.99
// }));
/**
* Exercise 10: Multi-Locale Application
* Create a localization system
*/
class I18n {
// TODO: Implement internationalization system
// constructor(defaultLocale)
// setLocale(locale): Change current locale
// getLocale(): Get current locale
// addTranslations(locale, translations): Add translation strings
// t(key, params): Translate key with parameters
// Params can include count for pluralization
// formatNumber(n, options)
// formatCurrency(n, currency)
// formatDate(date, options)
// formatRelativeTime(date)
// formatList(items)
}
// Test:
// const i18n = new I18n('en');
// i18n.addTranslations('en', {
// 'greeting': 'Hello, {name}!',
// 'items': { one: '{count} item', other: '{count} items' }
// });
// console.log(i18n.t('greeting', { name: 'World' }));
// console.log(i18n.t('items', { count: 5 }));
/**
* BONUS CHALLENGES
*/
/**
* Bonus 1: Calendar System Support
* Support different calendar systems
*/
function formatWithCalendar(date, locale, calendar) {
// TODO: Format date with specific calendar system
// Calendars: 'gregory', 'islamic', 'hebrew', 'chinese', etc.
}
/**
* Bonus 2: Smart Number Input
* Parse numbers from locale-specific formats
*/
function parseLocalizedNumber(str, locale) {
// TODO: Parse "1.234,56" (de-DE) or "1,234.56" (en-US) to number
// Handle currency symbols, percent signs, etc.
}
/**
* Bonus 3: Locale Negotiation
* Find best matching locale from available options
*/
function negotiateLocale(requestedLocales, availableLocales, defaultLocale) {
// TODO: Find best match between requested and available
// Consider language, region, and fallbacks
}
// ============================================
// SOLUTION KEY (for reference)
// ============================================
/*
// Exercise 1 Solution:
function formatCurrency(amount, currencyCode, locale) {
const localeMap = {
USD: 'en-US',
EUR: 'de-DE',
GBP: 'en-GB',
JPY: 'ja-JP',
CNY: 'zh-CN'
};
const useLocale = locale || localeMap[currencyCode] || 'en-US';
return new Intl.NumberFormat(useLocale, {
style: 'currency',
currency: currencyCode
}).format(amount);
}
// Exercise 2 Solution:
function createNumberFormatter(locale) {
return {
format(n) {
return new Intl.NumberFormat(locale).format(n);
},
percent(n) {
return new Intl.NumberFormat(locale, {
style: 'percent',
minimumFractionDigits: 0
}).format(n);
},
compact(n) {
return new Intl.NumberFormat(locale, {
notation: 'compact',
compactDisplay: 'short'
}).format(n);
},
scientific(n) {
return new Intl.NumberFormat(locale, {
notation: 'scientific'
}).format(n);
},
currency(n, code) {
return new Intl.NumberFormat(locale, {
style: 'currency',
currency: code
}).format(n);
}
};
}
// Exercise 4 Solution:
function relativeTime(date, baseDate = new Date(), locale = 'en') {
const rtf = new Intl.RelativeTimeFormat(locale, { numeric: 'auto' });
const diffMs = date.getTime() - baseDate.getTime();
const diffSeconds = Math.round(diffMs / 1000);
const units = [
['year', 60 * 60 * 24 * 365],
['month', 60 * 60 * 24 * 30],
['week', 60 * 60 * 24 * 7],
['day', 60 * 60 * 24],
['hour', 60 * 60],
['minute', 60],
['second', 1]
];
for (const [unit, seconds] of units) {
if (Math.abs(diffSeconds) >= seconds || unit === 'second') {
const value = Math.round(diffSeconds / seconds);
return rtf.format(value, unit);
}
}
}
// Exercise 6 Solution:
class Pluralizer {
constructor(locale) {
this.locale = locale;
this.rules = new Map();
this.pr = new Intl.PluralRules(locale);
}
addRule(key, forms) {
this.rules.set(key, forms);
}
format(key, count) {
const forms = this.rules.get(key);
if (!forms) return `${count} ${key}`;
const category = this.pr.select(count);
const template = forms[category] || forms.other;
return template.replace('#', count.toString());
}
}
// Exercise 7 Solution:
function createSorter(locale, options = {}) {
const collator = new Intl.Collator(locale, options);
return function(array, key = null) {
return [...array].sort((a, b) => {
const valA = key ? a[key] : a;
const valB = key ? b[key] : b;
return collator.compare(String(valA), String(valB));
});
};
}
*/
console.log('Complete the exercises above!');
console.log('Check the solution key at the bottom for guidance.');