![]() |
Country Generator 3.3.2
Procedural country generation for C++23
|
Where the data in resources/*/ comes from and how it is built: countries.tsv, then the locale tables (locales, time zones, currencies and holidays), below. For using the library, see the usage guide.
| Tier | Countries | Which |
|---|---|---|
lite | 195 | Independent (sovereign) states |
full | 250 | Every country and territory in the sources |
| Columns | Source |
|---|---|
| ISO codes, names, area, flag | mledoze/countries |
| Coordinates, region and subregion, capital, languages, currency, borders, demonyms, dialling codes, TLD, landlocked, independent, UN member | REST Countries v3.1, falling back to mledoze where REST Countries has no value |
| Population, timezones, continents, driving side, start of week | REST Countries only |
income_level | World Bank income classification |
language_shares | Unicode CLDR territoryInfo (Unicode License v3), added by scripts/prepare_language_shares.py; names CLDR lacks come from the SIL ISO 639-3 code table |
scripts/prepare_countries.py downloads all three, merges them by ISO alpha-3 code and writes both tiers:
After changing the data, run make embed to regenerate the compiled-in copy, and update the known-answer tests (the data hash and results change).
Lists (capital, continent, languages, borders, timezones) are separated by ;. Flags are 1 or 0.
| Column | Meaning | Notes |
|---|---|---|
cca2, cca3, ccn3 | ISO 3166-1 alpha-2, alpha-3 and numeric codes | cca2 is the key of extension layers |
name_common, name_official | English names | |
capital | Capital city or cities | |
region, subregion, continent | UN geoscheme region and subregion; continent(s) | region drives the country_request::region filter |
latitude, longitude | Representative point, decimal degrees | |
area | Land area in km² | -1 in the source means unknown (Svalbard and Jan Mayen) and reads as 0 |
population | Total population | Selection weight; a population of 0 (5 territories in full) counts as 1, so every country can be drawn |
landlocked, independent, un_member | Flags | |
language_shares | Name:percent pairs, largest first | Optional. The share of the population that speaks each language (CLDR's estimates, at least 1%); shares overlap and can sum above 100. Each percent is above 0 and at most 100 |
languages, currency_*, borders, timezones, driving_side, tld, idd_*, demonym_*, flag_emoji, income_level, start_of_week | As named | May be empty; income_level is "Not classified" for some countries (Ethiopia, for example) |
timezones (UTC offsets) and start_of_week (REST Countries) stay for compatibility. The locale tables have better sources for both: a zone's IANA name and rules in zones.tsv, and a locale's first_day from CLDR in locales.tsv.
country_request::region).Both draw from the "country" stream split from the call seed, with dasmig-core's weighted choice and uniform integer, so the result is the same on every platform.
latitude and longitude are a representative point, not a centroid or the capital's location.Seven tables next to countries.tsv in each tier. Each names its sources and versions in its first lines. Loading them does not change anything get_country returns or its data_hash().
| Table | Rows in lite (full) | Key | Source |
|---|---|---|---|
locales.tsv | 499 (570) | country, tag | Unicode CLDR 47 (cldr-json) |
zones.tsv | 350 (421) | country, zone | IANA tzdata 2026f, as compiled in the PyPI tzdata package 2026.6; GeoNames cities1000 for the shares |
zone_links.tsv | 140 (131) | link | IANA's backward file; in lite also the zones of territories it leaves out (Europe/Jersey is Europe/London) |
currencies.tsv | 169 | code | ISO 4217 list one (published by SIX), the withdrawn codes countries.tsv still uses from list three; cash digits from CLDR |
holidays.tsv | 5,136 (6,611) | country, key, from_year | Inferred from python-holidays 0.107 |
holiday_events.tsv | 14,925 (16,108) | event, country, date | python-holidays' calendars, and countries' own dates |
holiday_years.tsv | 195 (250) | country | python-holidays' years per country, within 1970 to 2050 |
They are built by three scripts, which download their pinned sources and write both tiers:
Then make embed regenerates dasmig/countrygen_locale_data.hpp. Each rebuild is checked by the validation scripts below, and changes only the locale, zone and holiday known answers.
A country's locales are the languages CLDR's territoryInfo gives it that at least 1% of the population speaks, and that are official there in any form or spoken by at least 5%, and that CLDR has locale data for. So Canada has en-CA (87) and fr-CA (29), not Spanish or Punjabi; the United States has en-US and es-US.
| Column | Meaning |
|---|---|
country, tag | ISO alpha-2 code, and the BCP 47 tag, minimised with CLDR's likely subtags (zh-Hant-TW is zh-TW; sr-Latn-RS keeps its script) |
language, script, language_name | ISO 639 code; ISO 15924 script when the tag has one; the English name, as language_shares writes it |
share | Percent of the country that speaks the language (CLDR's estimate). Shares overlap, so they are relative weights: fr-CA is drawn 29 / (87 + 29) = 25% of the time |
basis | cldr: CLDR has the locale for the country. inherited: CLDR has only the language's formats, used with the country's own week and measurement data (en-AR). fallback: no language qualifies, so one row for the first of countries.tsv's languages, with the formats of a language CLDR has (en-HM, full only) |
date_short … date_full, time_short, time_medium | CLDR's Gregorian patterns (LDML). The long and full time patterns are left out, since they carry a zone name |
months, months_abbr, weekdays, weekdays_abbr, am, pm, eras | Names in the format context, ;-separated; months from January, weekdays from Sunday; abbreviated eras |
decimal, group, minus, number_pattern, currency_pattern, currency_spacing | The Latin number system's symbols, standard patterns and the text inserted next to a letter currency symbol |
currency_code, currency_symbol | The country's currency and this locale's symbol for it. This is countries.tsv's currency_code when it is on ISO 4217 list one, else CLDR's current tender. Palestine is the exception: countries.tsv has EGP, the first of the currencies mledoze lists, and the locale has ILS, the currency the country uses and reports its statistics in |
first_day, weekend_start, weekend_end, measurement | CLDR's week data and measurement system for the country |
The build resolves CLDR's inheritance chain (en-NG → en-001 → en), so every row is complete. It rewrites the flexible day period B to a (AM and PM) where CLDR uses it, and fails on any pattern field the formatter does not support. A CLDR locale with no confirmed Gregorian data of its own, which cldr-json fills with the root locale's placeholders (months M01 to M12), is left out; 28 locales in lite were, among them dv-MV, la-VA and ny-MW, and every country kept a locale.
| Column | Meaning |
|---|---|
country, zone | ISO alpha-2 code and IANA zone name |
share | Percent of the country's population (GeoNames places of at least 1,000 people) in the zone; a zone with no such place gets the country's smallest share, so it can be drawn |
basis | tzdata: IANA's zone.tab lists it for the country. geonames: IANA lists no zone for the country, so its places' zones are used (Kosovo: Europe/Belgrade). fallback: neither has one, so a fixed Etc zone from countries.tsv's first UTC offset (BV and HM in full) |
periods, posix | The rules in core::tz_rules' text form: each offset change from the tier's start (2000 in lite, 1970 in full) to the last one the POSIX rule does not give, then that rule for every year after |
The rules are read from the compiled TZif files, not from the operating system, so they are the same on every platform.
| Column | Meaning |
|---|---|
code, numeric | ISO 4217 alphabetic and numeric codes |
digits | ISO 4217 minor unit (0 for JPY, 3 for KWD). ISO, not CLDR, which deliberately differs for a few currencies (it gives IQD 0 digits, ISO 3) |
cash_digits | Optional: CLDR's digits for cash where they differ |
A holiday here is a national day off, or a named day for observances, as python-holidays gives it for the country with no subdivision. Regional holidays (German states, US states) are not included: the UK gives the holidays common to its four nations, Germany its nine national ones.
| Column | Meaning |
|---|---|
country, key | ISO alpha-2 code, and a stable key in snake case (christmas_day) |
name, name_en | The name in the country's default language, as python-holidays writes it, and in English. Empty names repeat those of the row above, which has the same country and key |
kind | public, bank, optional (python-holidays' optional, government and half_day) or observance (unofficial) |
rule | MM-DD; MM:N:DOW, the N-th weekday (11:4:thu; -1 is the last); MM-DD>DOW or MM-DD<DOW, that weekday on or after, or before; easter+N and orthodox+N; event:KEY+N, a date of holiday_events.tsv |
days | Consecutive days from the date (Saudi Arabia's Eid al-Fitr holiday is 4) |
observed | What a weekend does: none; sun>mon; sat<fri,sun>mon (US federal); sat>mon,sun>mon (UK); next_weekday; weekend>next (a multi-day holiday gains a day); or a map of weekdays (tue<mon,thu>fri, Angola's bridge days). An ,overlap suffix moves onto a taken day too. The weekend is the country's own, from CLDR |
from_year, to_year | The years the rule holds, which is how law changes are kept (US Juneteenth from 2021) |
holiday_events.tsv holds the dates no rule computes: the Islamic, Chinese, Hebrew, Hindu and Buddhist calendars, Japan's equinoxes, and each country's own announced or decreed days. A row with country * is the shared date; a row with a country overrides it for that country, as Islamic dates follow moon sightings. holiday_years.tsv gives the span each country is served for: python-holidays' years within 1970 to 2050, so 1991 on for Germany and 2001 to 2035 for India.
Inference. prepare_holidays.py reads every country and year from python-holidays, groups the dates into one series per holiday, and fits the fewest rules that explain them: fixed dates, weekdays, Easter offsets, then calendar events. It fits the observed policy year by year. Then it evaluates the rules as the library does and compares them with python-holidays for every country, year and kind. A year whose moved days no policy reproduces (a decree) is written with none, and python-holidays' moved days become the country's own event. The result has no difference from python-holidays in either tier.
Countries without holidays. BV, HM and IO (all in full only) have a span but no holidays, which is not the same as not being covered. Ukraine has no public holidays from 2023, under martial law.
Run by hand at each rebuild, with the pinned versions of the sources; make dump builds the binary they read the library's answers from.
| Script | Compares with | Result (both tiers) |
|---|---|---|
scripts/validate_zones.py | Python's zoneinfo on the same IANA release: every transition from the tier's start to 2037, and zoneinfo's own changes, found by sampling every day | No difference |
scripts/validate_holidays.py | python-holidays 0.107, every country, year and kind | No difference |
scripts/validate_formats.py | Babel at the same CLDR version, 1,000 dates, times, numbers and amounts per locale, given the row's own data | No difference, after normalising three things Babel does not do: currency spacing, the locale's minus sign and ISO digits |
scripts/validate_locales.py | user-generator's hand-written locales | A report only |
zones.tsv ends with tzdata 2026f's rules; later changes need a rebuild.