|
| 1 | +# @lingo.dev/locales |
| 2 | + |
| 3 | +A JavaScript package that helps developers work with locale codes (like "en-US" or "zh-Hans-CN") and get country/language names in different languages. |
| 4 | + |
| 5 | +## Features |
| 6 | + |
| 7 | +- **Locale Parsing**: Break apart locale strings into language, script, and region components |
| 8 | +- **Validation**: Check if locale codes are properly formatted and use real ISO codes |
| 9 | +- **Name Resolution**: Get localized names for countries, languages, and scripts in 200+ languages |
| 10 | +- **Small Bundle Size**: Core package is ~12KB with on-demand data loading |
| 11 | +- **Full TypeScript Support**: Complete type definitions included |
| 12 | + |
| 13 | +## Installation |
| 14 | + |
| 15 | +```bash |
| 16 | +npm install @lingo.dev/locales |
| 17 | +``` |
| 18 | + |
| 19 | +## Usage |
| 20 | + |
| 21 | +### Locale Parsing |
| 22 | + |
| 23 | +```typescript |
| 24 | +import { |
| 25 | + parseLocale, |
| 26 | + getLanguageCode, |
| 27 | + getScriptCode, |
| 28 | + getRegionCode, |
| 29 | +} from "@lingo.dev/locales"; |
| 30 | + |
| 31 | +// Parse complete locale |
| 32 | +parseLocale("en-US"); // { language: "en", region: "US" } |
| 33 | +parseLocale("zh-Hans-CN"); // { language: "zh", script: "Hans", region: "CN" } |
| 34 | +parseLocale("sr-Cyrl-RS"); // { language: "sr", script: "Cyrl", region: "RS" } |
| 35 | + |
| 36 | +// Extract individual components |
| 37 | +getLanguageCode("en-US"); // "en" |
| 38 | +getScriptCode("zh-Hans-CN"); // "Hans" |
| 39 | +getRegionCode("en-US"); // "US" |
| 40 | +``` |
| 41 | + |
| 42 | +### Validation |
| 43 | + |
| 44 | +```typescript |
| 45 | +import { |
| 46 | + isValidLocale, |
| 47 | + isValidLanguageCode, |
| 48 | + isValidScriptCode, |
| 49 | + isValidRegionCode, |
| 50 | +} from "@lingo.dev/locales"; |
| 51 | + |
| 52 | +// Validate complete locales |
| 53 | +isValidLocale("en-US"); // true |
| 54 | +isValidLocale("en-FAKE"); // false |
| 55 | +isValidLocale("xyz-US"); // false |
| 56 | + |
| 57 | +// Validate individual components |
| 58 | +isValidLanguageCode("en"); // true |
| 59 | +isValidLanguageCode("xyz"); // false |
| 60 | +isValidScriptCode("Hans"); // true |
| 61 | +isValidScriptCode("Fake"); // false |
| 62 | +isValidRegionCode("US"); // true |
| 63 | +isValidRegionCode("ZZ"); // false |
| 64 | +``` |
| 65 | + |
| 66 | +### Name Resolution (Async) |
| 67 | + |
| 68 | +```typescript |
| 69 | +import { |
| 70 | + getCountryName, |
| 71 | + getLanguageName, |
| 72 | + getScriptName, |
| 73 | +} from "@lingo.dev/locales"; |
| 74 | + |
| 75 | +// Get country names in different languages |
| 76 | +await getCountryName("US"); // "United States" |
| 77 | +await getCountryName("US", "es"); // "Estados Unidos" |
| 78 | +await getCountryName("CN", "fr"); // "Chine" |
| 79 | + |
| 80 | +// Get language names in different languages |
| 81 | +await getLanguageName("en"); // "English" |
| 82 | +await getLanguageName("en", "es"); // "inglés" |
| 83 | +await getLanguageName("zh", "fr"); // "chinois" |
| 84 | + |
| 85 | +// Get script names in different languages |
| 86 | +await getScriptName("Hans"); // "Simplified Han" |
| 87 | +await getScriptName("Hans", "es"); // "han simplificado" |
| 88 | +await getScriptName("Latn", "zh"); // "拉丁文" |
| 89 | +``` |
| 90 | + |
| 91 | +## API Reference |
| 92 | + |
| 93 | +### Parsing Functions |
| 94 | + |
| 95 | +#### `parseLocale(locale: string): LocaleComponents` |
| 96 | + |
| 97 | +Breaks apart a locale string into its components. |
| 98 | + |
| 99 | +**Parameters:** |
| 100 | + |
| 101 | +- `locale` (string): The locale string to parse |
| 102 | + |
| 103 | +**Returns:** `LocaleComponents` object with `language`, `script`, and `region` properties |
| 104 | + |
| 105 | +**Examples:** |
| 106 | + |
| 107 | +```typescript |
| 108 | +parseLocale("en-US"); // { language: "en", region: "US" } |
| 109 | +parseLocale("zh-Hans-CN"); // { language: "zh", script: "Hans", region: "CN" } |
| 110 | +parseLocale("es"); // { language: "es" } |
| 111 | +``` |
| 112 | + |
| 113 | +#### `getLanguageCode(locale: string): string` |
| 114 | + |
| 115 | +Extracts just the language part from a locale string. |
| 116 | + |
| 117 | +#### `getScriptCode(locale: string): string | null` |
| 118 | + |
| 119 | +Extracts the script part from a locale string. |
| 120 | + |
| 121 | +#### `getRegionCode(locale: string): string | null` |
| 122 | + |
| 123 | +Extracts the region/country part from a locale string. |
| 124 | + |
| 125 | +### Validation Functions |
| 126 | + |
| 127 | +#### `isValidLocale(locale: string): boolean` |
| 128 | + |
| 129 | +Checks if a locale string is properly formatted and uses real codes. |
| 130 | + |
| 131 | +#### `isValidLanguageCode(code: string): boolean` |
| 132 | + |
| 133 | +Checks if a language code is valid (ISO 639-1). |
| 134 | + |
| 135 | +#### `isValidScriptCode(code: string): boolean` |
| 136 | + |
| 137 | +Checks if a script code is valid (ISO 15924). |
| 138 | + |
| 139 | +#### `isValidRegionCode(code: string): boolean` |
| 140 | + |
| 141 | +Checks if a region code is valid (ISO 3166-1 alpha-2 or UN M.49). |
| 142 | + |
| 143 | +### Name Resolution Functions |
| 144 | + |
| 145 | +#### `getCountryName(countryCode: string, displayLanguage = "en"): Promise<string>` |
| 146 | + |
| 147 | +Gets a country name in the specified language. |
| 148 | + |
| 149 | +**Parameters:** |
| 150 | + |
| 151 | +- `countryCode` (string): The country code (e.g., "US", "CN") |
| 152 | +- `displayLanguage` (string, optional): The language to display the name in (default: "en") |
| 153 | + |
| 154 | +**Returns:** Promise<string> - The localized country name |
| 155 | + |
| 156 | +#### `getLanguageName(languageCode: string, displayLanguage = "en"): Promise<string>` |
| 157 | + |
| 158 | +Gets a language name in the specified language. |
| 159 | + |
| 160 | +#### `getScriptName(scriptCode: string, displayLanguage = "en"): Promise<string>` |
| 161 | + |
| 162 | +Gets a script name in the specified language. |
| 163 | + |
| 164 | +## Supported Formats |
| 165 | + |
| 166 | +The package supports both hyphen (`-`) and underscore (`_`) delimiters: |
| 167 | + |
| 168 | +- `en-US` or `en_US` → `{ language: "en", region: "US" }` |
| 169 | +- `zh-Hans-CN` or `zh_Hans_CN` → `{ language: "zh", script: "Hans", region: "CN" }` |
| 170 | + |
| 171 | +## Data Sources |
| 172 | + |
| 173 | +- **Locale parsing**: Uses regex-based parsing with ISO standard validation |
| 174 | +- **Name resolution**: Uses Unicode CLDR (Common Locale Data Repository) data |
| 175 | +- **Validation**: Uses official ISO 639-1, ISO 15924, and ISO 3166-1 standards |
| 176 | + |
| 177 | +## Performance |
| 178 | + |
| 179 | +- **Bundle size**: Core package is ~12KB (ESM) / ~14KB (CJS) |
| 180 | +- **Runtime data**: Loaded on-demand from GitHub raw URLs |
| 181 | +- **Caching**: In-memory cache to avoid repeated network requests |
| 182 | +- **Fallback**: Graceful degradation to English when language data is unavailable |
| 183 | + |
| 184 | +## Error Handling |
| 185 | + |
| 186 | +All functions include comprehensive error handling: |
| 187 | + |
| 188 | +```typescript |
| 189 | +try { |
| 190 | + parseLocale("invalid"); |
| 191 | +} catch (error) { |
| 192 | + console.log(error.message); // "Invalid locale format: invalid" |
| 193 | +} |
| 194 | + |
| 195 | +try { |
| 196 | + await getCountryName("XX"); |
| 197 | +} catch (error) { |
| 198 | + console.log(error.message); // "Country code "XX" not found" |
| 199 | +} |
| 200 | +``` |
| 201 | + |
| 202 | +## TypeScript Support |
| 203 | + |
| 204 | +Full TypeScript support with comprehensive type definitions: |
| 205 | + |
| 206 | +```typescript |
| 207 | +interface LocaleComponents { |
| 208 | + language: string; |
| 209 | + script?: string; |
| 210 | + region?: string; |
| 211 | +} |
| 212 | + |
| 213 | +type LocaleDelimiter = "-" | "_"; |
| 214 | + |
| 215 | +interface ParseResult { |
| 216 | + components: LocaleComponents; |
| 217 | + delimiter: LocaleDelimiter | null; |
| 218 | + isValid: boolean; |
| 219 | + error?: string; |
| 220 | +} |
| 221 | +``` |
| 222 | + |
| 223 | +## License |
| 224 | + |
| 225 | +Apache 2.0 |
0 commit comments