/

countries-list GitHub

Дані країн, мов та континентів у форматах ISO (столиці, валюти, назви рідною мовою, телефонні коди).

3.0M/mo 1.3K typescripti18nisodataopen-sourcenpmphp
bun add countries-list

Випадний список країн — найнудніше, що можна зробити, і у 2014-му я не міг знайти даних, щоб його нормально заповнити. В одних списках були англійські назви, але не було назв рідною мовою, в інших — коди ISO, але без телефонних; а де було все одразу, там воно лежало в багатомегабайтному файлі, зібраному для зовсім іншої задачі.

Тож я зібрав свій, і відтоді ідея не змінилася: один типізований запис на країну — код, назва, назва рідною мовою, столиця, валюта, телефонний код, континент — і нічого зайвого.

Приклади

import { continents, countries, getCountryCode, getEmojiFlag, languages } from 'countries-list'

countries.UA
// { name: 'Ukraine', native: 'Україна', phone: [380], continent: 'EU',
//   capital: 'Kyiv', currency: ['UAH'], languages: ['uk'] }

getCountryCode('Ukraine') // 'UA'
getCountryCode('Україна') // 'UA' — рідні назви теж працюють
getEmojiFlag('UA')        // '🇺🇦'
continents.EU             // 'Europe'
languages.uk              // { name: 'Ukrainian', native: 'Українська' }

Кожен код ISO 3166-1 і навіть трохи більше, жодних залежностей, типи в комплекті. countries. автодоповнюється в редакторі, а одрук у коді країни стає помилкою компіляції, а не undefined під час виконання — коди з форми чи API все одно варто перевіряти окремо.

Навіщо це

Проблема ніколи не була в назвах країн — їх вистачає всюди. Проблема в тому, що полю країни одночасно потрібні чотири різні речі: код, щоб зберегти, назва, щоб показати, прапор, щоб намалювати, і телефонний код для поля з номером. Зібрати це з трьох пакетів означало три набори ключів країн, які не збігаються між собою, плюс шар мапінгу, щоб їх помирити.

Коли всі поля лежать в одному записі, цілий клас таких помилок стає неможливим. Ідея не геніальна — мабуть, тому й досі корисна.

Чим відрізняється

У цій ніші є хороші набори даних, і вони розв’язують різні задачі:

ПакетПро що він
countries-listодин типізований запис на країну — коди, рідні назви, столиця, валюта, телефон, континент
i18n-iso-countriesназви країн, перекладені багатьма мовами
world-countriesвеликий сирий набір даних — кордони, координати, альтернативні написання
iso-3166-1конвертація кодів і принципово нічого більше

Беріть i18n-iso-countries, якщо вам потрібна «Німеччина» японською — переклад назв за локалями це його основна робота, і робить він її краще. Беріть world-countries, якщо потрібна географія. Цей пакет покриває поля, які питає форма чи екран налаштувань, і на цьому все.

Чого немає в інших: ті самі дані потрапляють у PHP через Packagist і генеруються з того самого джерела.

composer require annexare/countries-list

Що всередині

Валюти — окремим імпортом

Повний ISO 4217 — назви, назви рідною мовою, символи, числові коди, розмінні одиниці — живе за власним підшляхом:

import { currencies, getCurrency, getCurrencyByNumeric } from 'countries-list/currencies'

currencies.UAH
// { name: 'Ukrainian Hryvnia', native: 'українська гривня', symbol: '₴',
//   symbolNative: '₴', numeric: '980', decimals: 2 }

getCurrency('JPY')          // decimals: 0 — у єни немає розмінної одиниці
getCurrencyByNumeric('840') // USD, для банківських запитів з числовими кодами

Набір валют перегенеровується з офіційного списку ISO 4217 та CLDR скриптом, а не правиться руками, тож оновити його після зміни валюти — це команда, а не вечір роботи.

Мінімальні мапи для простих випадків

Іноді потрібні два кілобайти, а не набір даних:

import countries2to3 from 'countries-list/minimal/countries.2to3.min.json'
import languageNames from 'countries-list/minimal/languages.native.min.json'

Формати поза JavaScript

Ті самі дані генеруються як JSON, CSV і SQL, тож щоб заповнити базу, не треба спершу писати скрипт імпорту. Файли лежать усередині npm-пакета — нічого додатково завантажувати не треба:

mysql app_db < node_modules/countries-list/data.sql

head -2 node_modules/countries-list/countries.csv
# "Code","Name","Native","Phone","Continent","Capital","Currency","Languages"
# "AC","Ascension Island","Ascension Island","247","Africa","Georgetown","SHP","en"

Нотатки про рішення

Валюти винесені окремо не випадково. Повна таблиця ISO 4217 з рідними назвами й символами — це відчутна кількість байтів, і більшість застосунків, яким потрібен список країн, ніколи її не торкається. Тримати її за countries-list/currencies, а не в кореневому експорті, залишає типовий випадок легким. Експорти через підшляхи — найдешевше рішення для розміру бандла з усіх можливих, і саме те, яке більшість наборів даних пропускає.

ISO 4217 взагалі не визначає символів. Він стандартизує коди, числові коди та розмінні одиниці; і ¥ беруться з Unicode CLDR — окремого джерела зі своїм циклом оновлень. Якщо у валюти немає власного латинського знаку, symbol відкочується до коду ISO, а локальний знак іде в symbolNative: CHF лишається CHF, а JPY дає ¥ для латинського інтерфейсу і для японського. Об’єднати symbol і symbolNative в одне поле було б простіше — і неправильно, бо інтерфейсу потрібні обидва варіанти.

getCountryCode шукає не лише за англійською назвою. Він знаходить країну і за рідною назвою («Україна» → UA), і за поширеними альтернативними написаннями на кшталт USA чи UK. Це один додатковий індекс у даних, який робить набір придатним для форм будь-якою мовою — і тихо прибирає цілу категорію костилів.

Третю версію я повністю переписав на TypeScript, ESM і монорепозиторій на Bun workspaces. Усе в dist генерується з типізованих джерел, включно з SQL, тож виправлення даних — це одна правка в одному місці, а не чотири файли, які треба тримати синхронними вручну.

Статус

Проєкт живий, розвивається та підтримується з 2014-го — у тому числі користувачами, адже код відкритий.

Деталі

Автор
Dmytro Klymenko
Опубліковано
Annexare на GitHub, NPM, Packagist
Зроблено на
Bun — workspaces, збірка, тести, Unicode CLDR — символи валют
Початок
Оновлено

Інші проєкти