randNickname
Generates nicknames and returns count of them as strings. Each one is an everyday word with something added to it: an adjective in front, a verb in front, a second word behind, or a possessive between the two. Person names are never used. With output: 'detail' it reports the words it used instead.
import { randNickname } from 'randino';
randNickname();
// ['MistyOwl']import 'package:randino/randino.dart';
randNickname();
// ['MistyOwl']from randino import rand_nickname
rand_nickname()
# ['MistyOwl']Options
Every option is optional, and the defaults are what the empty call above uses.
| Option | Type | Default | Description |
|---|---|---|---|
language | WordLanguageOptionWordLanguage?WordLanguageOption | None | 'all'nullNone | Language of the generated nicknames. 'all'null"all" mixes every supported language, picking one per nickname. |
theme | WordThemeOptionWordTheme?WordThemeOption | 'all'null"all" | What the nickname is about. See Themes. |
slots | WordSlotOptionSet<WordSlot>?WordSlotOption | 'all'null"all" | Which shapes to accept, by what they put beside the noun. See Picking the shape. |
count | numberintint | 1 | How many nicknames to return. Clamped to 0 … 10000. |
realism | RandRealism | <Lang js="'real'" dart="RandRealism.real" py="\"real\"" /> | real uses real words, invented builds words that only read like the language, and mixed decides per word. |
vocabulary | RandVocabulary | <Lang js="'full'" dart="RandVocabulary.full" py="\"full\"" /> | How common the noun the nickname is built around has to be: basic, common or full. See Common words. |
minLengthminLengthmin_length | numberint?int | None | language | Minimum length in characters. |
maxLengthmaxLengthmax_length | numberint?int | None | language | Maximum length in characters. |
wordSeparatorwordSeparatorword_separator | stringString?str | None | language | Placed between the words. Counts toward the length range. Defaults to running them together. |
startsWithstartsWithstarts_with | stringString?str | —null"" | Keep only nicknames whose first character is this one. |
unique | booleanboolbool | falsefalseFalse | Never return the same nickname twice. May return fewer than count once the pools run out of combinations. |
output | RandOutputRandOutput | 'value'"value" | Strings, or a NicknameDetail per nickname. Dart has no such parameter — see the detail output. |
random | () => numberRandom?Callable[[], float] | None | —nullNone | Where the randomness comes from — see Choosing the source. Defaults to the platform's ordinary generator. |
The detail output
output: 'detail' reports the pieces each nickname was built from instead of returning a string: the words in order, the language and the theme. Use it to highlight the base word, or to group by theme.
Dart spells this as a second function, randNicknameDetails, because it has no way to make one function's return type depend on an argument. It takes the same parameters as randNickname.
import { randNickname } from 'randino';
randNickname({ language: 'en', output: 'detail' });
// [{
// nickname: 'MistyOwl',
// words: ['Misty', 'Owl'],
// slots: ['adjective', 'noun'],
// language: 'en',
// theme: 'animal'
// }]import 'package:randino/randino.dart';
randNicknameDetails(language: WordLanguage.en);
// [NicknameDetail(MistyOwl, [Misty, Owl], en, animal)]
randNicknameDetails(language: WordLanguage.en).first.slots;
// [WordSlot.adjective, WordSlot.noun]from randino import rand_nickname
rand_nickname(language="en", output="detail")
# [NicknameDetail(nickname='MistyOwl', words=('Misty', 'Owl'),
# slots=('adjective', 'noun'), language='en', theme='animal')]| Field | Type | Description |
|---|---|---|
nickname | stringStringstr | The finished nickname. |
words | string[]List<String>tuple[str, ...] | The words it is made of, in order — the words only. |
slots | WordSlot[]List<WordSlot>tuple[WordSlot, ...] | What each word does in the shape, at the same index as words. |
language | WordLanguage | The language this nickname was generated in. |
theme | WordTheme | nullWordTheme?WordTheme | None | Theme of the base word, or null when that word is not one the generator knows. |
slots lines up with words: the word at index 2 is the thing slots[2] names. Every shape has exactly one noun, and the rest is whatever the shape put beside it.
words holds the words and nothing else. A shape that needs a particle between two of them carries it in nickname alone, so 사자의눈물 reports ['사자', '눈물'] and joining the two back together does not reproduce it. Read nickname for the finished string, and words for what it was built from.
About theme
The theme is reported, not asserted. A word drawn from a theme reports it; an invented word is looked up across every theme, because it can spell a real one by accident, and reports null when it is found nowhere.
Two coincidences follow from that, and both are worth expecting rather than treating as bugs. A word can be both a modifier and a noun, as Marble is, and an invented word can spell a real one by accident: the syllable templates spell Snake now and then, so a nickname built at realism: 'invented' can come back with theme set to animal.
Examples
One language at a time
randNickname({ language: 'ko', count: 4 });
// ['오래된곰', '영원한도마뱀', '귀여운신화다발', '노을']
randNickname({ language: 'en', count: 4 });
// ['FoggyHillside', 'CraneVoyage', 'TinyLeopardCloak', 'MathematicsShard']
randNickname({ language: 'ja', count: 4 });
// ['小さな雨', '海の彗星', '鋭いペンギン', '柔らかい記憶']
randNickname({ language: 'zh', count: 4 });
// ['勇敢余烬', '快乐薄雾', '节日', '安静小狗']randNickname(language: WordLanguage.ko, count: 4);
// ['오래된곰', '영원한도마뱀', '귀여운신화다발', '노을']
randNickname(language: WordLanguage.en, count: 4);
// ['FoggyHillside', 'CraneVoyage', 'TinyLeopardCloak', 'MathematicsShard']
randNickname(language: WordLanguage.ja, count: 4);
// ['小さな雨', '海の彗星', '鋭いペンギン', '柔らかい記憶']
randNickname(language: WordLanguage.zh, count: 4);
// ['勇敢余烬', '快乐薄雾', '节日', '安静小狗']rand_nickname(language="ko", count=4)
# ['오래된곰', '영원한도마뱀', '귀여운신화다발', '노을']
rand_nickname(language="en", count=4)
# ['FoggyHillside', 'CraneVoyage', 'TinyLeopardCloak', 'MathematicsShard']
rand_nickname(language="ja", count=4)
# ['小さな雨', '海の彗星', '鋭いペンギン', '柔らかい記憶']
rand_nickname(language="zh", count=4)
# ['勇敢余烬', '快乐薄雾', '节日', '安静小狗']A theme
randNickname({ language: 'en', theme: 'animal', count: 3 });
// ['FloatingFalcon', 'ChewyOtter', 'PlacidMantis']
randNickname({ language: 'en', theme: 'gem', count: 3 });
// ['PolarObsidian', 'AmberGeode', 'QuietMalachite']randNickname(language: WordLanguage.en, theme: WordTheme.animal, count: 3);
// ['FloatingFalcon', 'ChewyOtter', 'PlacidMantis']
randNickname(language: WordLanguage.en, theme: WordTheme.gem, count: 3);
// ['PolarObsidian', 'AmberGeode', 'QuietMalachite']rand_nickname(language="en", theme="animal", count=3)
# ['FloatingFalcon', 'ChewyOtter', 'PlacidMantis']
rand_nickname(language="en", theme="gem", count=3)
# ['PolarObsidian', 'AmberGeode', 'QuietMalachite']The twenty-nine themes, and what each one holds, are on Themes.
Picking the shape
slots names what a shape may put beside the noun, and the shapes that use none of it are dropped. A shape qualifies when it uses at least one of the slots, so naming two asks for either and leaves the choice to chance, which is what ['adjective', 'action'] below does.
randNickname({ language: 'en', slots: 'action', count: 3 });
// ['CountingHarmonics', 'HaulingBurrito', 'FloatingSelkie']
randNickname({ language: 'en', slots: 'part', count: 3 });
// ['CardTrack', 'DreamyBlackthornBreeze', 'ThrowingParachuteHorn']
randNickname({ language: 'en', slots: ['adjective', 'action'], count: 3 });
// ['JadeOdyssey', 'DownyBreeze', 'MidnightFinchLair']
randNickname({ language: 'en', slots: 'none', count: 3 });
// ['Captain', 'Bronze', 'Clown']randNickname(language: WordLanguage.en, slots: {WordSlot.action}, count: 3);
// ['CountingHarmonics', 'HaulingBurrito', 'FloatingSelkie']
randNickname(language: WordLanguage.en, slots: {WordSlot.part}, count: 3);
// ['CardTrack', 'DreamyBlackthornBreeze', 'ThrowingParachuteHorn']
randNickname(
language: WordLanguage.en,
slots: {WordSlot.adjective, WordSlot.action},
count: 3,
);
// ['JadeOdyssey', 'DownyBreeze', 'MidnightFinchLair']
// The empty set is what `'none'` spells in the other two packages.
randNickname(language: WordLanguage.en, slots: {}, count: 3);
// ['Captain', 'Bronze', 'Clown']rand_nickname(language="en", slots="action", count=3)
# ['CountingHarmonics', 'HaulingBurrito', 'FloatingSelkie']
rand_nickname(language="en", slots="part", count=3)
# ['CardTrack', 'DreamyBlackthornBreeze', 'ThrowingParachuteHorn']
rand_nickname(language="en", slots=("adjective", "action"), count=3)
# ['JadeOdyssey', 'DownyBreeze', 'MidnightFinchLair']
rand_nickname(language="en", slots="none", count=3)
# ['Captain', 'Bronze', 'Clown']A language answers with what it has. The shapes are the language's own, so not every one of them can answer every request: Spanish, Italian, German and Russian have no trailing-noun shape, because cola de gato needs a preposition rather than a joiner. Asking one of them for part falls back to every shape it does have, the same way a length range too narrow for a shape is answered with the closest fit rather than with an error.
randNickname({ language: 'de', slots: 'part', count: 3 });
// ['klingender Obstler', 'freier Geysir', 'wilder Drache']randNickname(language: WordLanguage.de, slots: {WordSlot.part}, count: 3);
// ['klingender Obstler', 'freier Geysir', 'wilder Drache']rand_nickname(language="de", slots="part", count=3)
# ['klingender Obstler', 'freier Geysir', 'wilder Drache']With no language named, the ones that can answer are preferred over the ones that cannot, so asking every language for a trailing noun draws from the five that have one.
A separator between the words
randNickname({ language: 'en', wordSeparator: ' ', count: 4 });
// ['Soldier', 'Hollow Petal', 'Syrupy Mica Tale', 'Spinning Cathedral']
randNickname({ language: 'en', wordSeparator: '-', count: 4 });
// ['Headphone', 'Soft-Bat', 'Genial-Moose-Cove', 'Dreamy-Umbrella-Halo']randNickname(language: WordLanguage.en, wordSeparator: ' ', count: 4);
// ['Soldier', 'Hollow Petal', 'Syrupy Mica Tale', 'Spinning Cathedral']
randNickname(language: WordLanguage.en, wordSeparator: '-', count: 4);
// ['Headphone', 'Soft-Bat', 'Genial-Moose-Cove', 'Dreamy-Umbrella-Halo']rand_nickname(language="en", word_separator=" ", count=4)
# ['Soldier', 'Hollow Petal', 'Syrupy Mica Tale', 'Spinning Cathedral']
rand_nickname(language="en", word_separator="-", count=4)
# ['Headphone', 'Soft-Bat', 'Genial-Moose-Cove', 'Dreamy-Umbrella-Halo']Its length counts toward minLengthminLengthmin_length and maxLengthmaxLengthmax_length. Pass it to nicknameLengthRange to see what is left.
A unique suffix
There is no option for one. randSuffix attaches a random token to whatever you hand it, these nicknames included.
randSuffix(randNickname({ language: 'en', count: 3 }));
// ['RoundSeason_RVBnC', 'RowdyDusk_dwtu5', 'RovingLakeShard_QqMVH']
randSuffix(randNickname({ language: 'en', count: 2 }), { length: 8, separator: '-' });
// ['GenialFern-9xq9SgJf', 'BoldBicycle-PGc4keqM']randSuffixAll(randNickname(language: WordLanguage.en, count: 3));
// ['RoundSeason_RVBnC', 'RowdyDusk_dwtu5', 'RovingLakeShard_QqMVH']
randSuffixAll(
randNickname(language: WordLanguage.en, count: 2),
length: 8,
separator: '-',
);
// ['GenialFern-9xq9SgJf', 'BoldBicycle-PGc4keqM']rand_suffix(rand_nickname(language="en", count=3))
# ['RoundSeason_RVBnC', 'RowdyDusk_dwtu5', 'RovingLakeShard_QqMVH']
rand_suffix(rand_nickname(language="en", count=2), length=8, separator="-")
# ['GenialFern-9xq9SgJf', 'BoldBicycle-PGc4keqM']Because it happens afterwards, minLengthminLengthmin_length / maxLengthmaxLengthmax_length describe the whole nickname rather than the part in front of a suffix.
Invented words
randNickname({ language: 'en', realism: 'invented', count: 3 });
// ['Duhusk', 'DresaelSlobru', 'BroureexGrosex']randNickname(language: WordLanguage.en, realism: RandRealism.invented, count: 3);
// ['Duhusk', 'DresaelSlobru', 'BroureexGrosex']rand_nickname(language="en", realism="invented", count=3)
# ['Duhusk', 'DresaelSlobru', 'BroureexGrosex']Highlighting the base word
for (const { words, theme } of randNickname({ language: 'en', count: 3, output: 'detail' })) {
console.log(words.join(' + '), theme);
}
// Grumpy + Zither music
// Fierce + Printer product
// Endless + Obsidian + Wing gemfor (final detail in randNicknameDetails(language: WordLanguage.en, count: 3)) {
print('${detail.words.join(' + ')} ${detail.theme?.name}');
}
// Grumpy + Zither music
// Fierce + Printer product
// Endless + Obsidian + Wing gemfor detail in rand_nickname(language="en", count=3, output="detail"):
print(" + ".join(detail.words), detail.theme)
# Grumpy + Zither music
# Fierce + Printer product
# Endless + Obsidian + Wing gemStoring the readable part and the discriminator
A sign-up flow usually wants the readable part and the collision-breaking part in two columns, so that a later rename can keep one and replace the other. randSuffix is what makes the second one, and it never has to be pulled back out of the first:
const [detail] = randNickname({ language: 'en', output: 'detail' });
const discriminator = randSuffix('', { separator: '' });
await users.insert({
handle: `${detail.nickname}_${discriminator}`,
display: detail.nickname,
discriminator
});final detail = randNicknameDetails(language: WordLanguage.en).first;
final discriminator = randSuffix('', separator: '');
await users.insert(
handle: '${detail.nickname}_$discriminator',
display: detail.nickname,
discriminator: discriminator,
);detail = rand_nickname(language="en", output="detail")[0]
discriminator = rand_suffix("", separator="")
await users.insert(
handle=f"{detail.nickname}_{discriminator}",
display=detail.nickname,
discriminator=discriminator,
)Grouping by theme
const byTheme = {};
for (const detail of randNickname({ language: 'en', count: 100, output: 'detail' })) {
(byTheme[detail.theme] ??= []).push(detail.nickname);
}final byTheme = <WordTheme?, List<String>>{};
for (final detail in randNicknameDetails(language: WordLanguage.en, count: 100)) {
byTheme.putIfAbsent(detail.theme, () => <String>[]).add(detail.nickname);
}from collections import defaultdict
by_theme: defaultdict[WordTheme | None, list[str]] = defaultdict(list)
for detail in rand_nickname(language="en", count=100, output="detail"):
by_theme[detail.theme].append(detail.nickname)See also
randSuffix— the random token, for when a nickname has to be collision-free.- Themes — the twenty-nine slices of vocabulary a nickname is built from.
nicknameLengthRange— every length a language can produce.