How to serve locale-specific data
You want the same generator definition to produce Turkish cities under one locale and American cities under another — without branching in the schema. In Phony the generator is fixed; only the active locale chain changes, and the asset it reads resolves to different data per locale.
How resolution works
An asset is a name (like demo.cities) mapped to per-locale data. When a generator reads it, Phony walks the active chain most-specific first, and if no entry matches, falls back to the locale-independent * entry:
domain > locale > base (*)So a chain of ["tr_TR"] tries tr_TR, then *. A chain of ["fr_FR","en_US"] tries fr_FR, then en_US, then *. The * fallback is always tried last, even when you didn't put it in the chain. Adding a locale to an asset never affects how any other locale resolves.
Steps
- In a package's
assetsblock, map an asset name to{ locale → data }, including a*fallback. - Write a generator that reads the asset by name (
{ "type": "list", "source": "<asset>" }). - Run
phony generatewith--locale, a comma-separated chain, most-specific first.
Complete example
locale-pkg/phony.json — one generator, one asset, three locales:
{
"name": "@demo/geo",
"version": "0.1.0",
"generators": [
{ "name": "@demo/geo:city", "body": "{{ city }}",
"let": { "city": { "type": "list", "source": "demo.cities" } } }
],
"assets": {
"lists": {
"demo.cities": {
"tr_TR": ["İstanbul", "Ankara", "İzmir", "Bursa"],
"en_US": ["New York", "Chicago", "Denver", "Austin"],
"*": ["Metropolis", "Gotham", "Springfield"]
}
}
}
}The same command, two locales:
phony generate --use @demo/geo:city --package ./locale-pkg --locale tr_TR --seed 42 -n 4 -f jsonl"Bursa"
"Ankara"
"Ankara"
"Ankara"phony generate --use @demo/geo:city --package ./locale-pkg --locale en_US --seed 42 -n 4 -f jsonl"Austin"
"Chicago"
"Chicago"
"Chicago"Byte-for-byte the same definition and the same seed — only the chain changed, so only the resolved data differs.
Fallback in action
Omit --locale entirely and the chain is just *:
phony generate --use @demo/geo:city --package ./locale-pkg --seed 42 -n 4 -f jsonl"Metropolis"
"Metropolis"
"Gotham"
"Springfield"Pass a chain whose most-specific locale is missing, and resolution walks down it. demo.cities has no fr_FR, so fr_FR,en_US resolves through to the US data:
phony generate --use @demo/geo:city --package ./locale-pkg --locale fr_FR,en_US --seed 42 -n 4 -f jsonl"Austin"
"Chicago"
"Chicago"
"Chicago"Contributing a locale to someone else's asset
Because assets merge by (asset, locale), a package can add a locale to an asset another package already defines — without either touching the other. A data-only package that adds Azerbaijani cities to demo.cities:
{
"name": "@aziz/az-cities",
"version": "0.1.0",
"assets": {
"lists": {
"demo.cities": {
"az_AZ": ["Bakı", "Gəncə", "Sumqayıt", "Mingəçevir"]
}
}
}
}Load both packages (--package ./locale-pkg --package ./az-cities) and --locale az_AZ now resolves to the contributed list. Later --package directories layer on top of earlier ones.
Models are locale-polymorphic too
The same shape works for trained N-gram models under assets.models — a { "type": "model", "source": "person.first_names" } generator can resolve a Turkish model under tr_TR and an English one under en_US, invented novel names instead of picking from a fixed list. Train a model with phony train (see the CLI reference) and point each locale at its .ngram file:
{ "assets": { "models": { "person.first_names": {
"tr_TR": "models/tr_first_names.ngram",
"en_US": "models/en_first_names.ngram"
} } } }Pitfalls
*is always the last resort, tried after every locale in the chain — so give every asset a sensible*entry, or a lookup with no matching locale returns nothing and the generator errors.- The chain is most-specific first.
--locale en_US,tr_TRprefers English and only falls back to Turkish; reverse it to prefer Turkish. - A "domain" is just a more-specific chain entry (e.g. put a domain tag ahead of the locale). There's no separate domain flag — it's the same precedence list.
- Locale tags are opaque strings.
tr_TRandtrare different keys; be consistent between your asset keys and your--localechain.