Expose supported identity language options via identity-generator shared lib (#1379)

This commit is contained in:
Leendert de Borst
2025-11-21 10:27:23 +01:00
committed by Leendert de Borst
parent a30e68e0f8
commit 274cb70d4b
19 changed files with 984 additions and 45 deletions

View File

@@ -0,0 +1,239 @@
declare enum Gender {
Male = "Male",
Female = "Female",
Other = "Other"
}
/**
* Identity.
*/
type Identity = {
firstName: string;
lastName: string;
gender: Gender;
birthDate: Date;
emailPrefix: string;
nickName: string;
};
/**
* Options for birthdate generation.
*/
interface IBirthdateOptions {
/**
* The target year for the birthdate (e.g., 1990).
*/
targetYear: number;
/**
* The random deviation in years (e.g., 5 means ±5 years from targetYear).
* If 0, a random date within the target year will be chosen.
*/
yearDeviation: number;
}
interface IIdentityGenerator {
generateRandomIdentity(gender?: string | 'random', birthdateOptions?: IBirthdateOptions): Identity;
}
/**
* Dictionary of firstnames organized by decade range.
*/
interface IDecadeFirstnames {
startYear: number;
endYear: number;
names: string[];
}
/**
* Base identity generator.
*/
declare abstract class IdentityGenerator implements IIdentityGenerator {
protected firstNamesMale: string[];
protected firstNamesFemale: string[];
protected lastNames: string[];
private readonly random;
/**
* Constructor.
*/
constructor();
protected abstract getFirstNamesMaleJson(): string[];
protected abstract getFirstNamesFemaleJson(): string[];
protected abstract getLastNamesJson(): string[];
/**
* Get decade-based male first names. Override this to provide age-specific names.
* If not overridden, returns an empty array and falls back to generic names.
*/
protected getFirstNamesMaleByDecade(): IDecadeFirstnames[];
/**
* Get decade-based female first names. Override this to provide age-specific names.
* If not overridden, returns an empty array and falls back to generic names.
*/
protected getFirstNamesFemaleByDecade(): IDecadeFirstnames[];
/**
* Generate a random date of birth.
* @param birthdateOptions Optional birthdate configuration
*/
protected generateRandomDateOfBirth(birthdateOptions?: IBirthdateOptions): Date;
/**
* Select appropriate firstnames based on birthdate.
* Falls back to generic names if no decade-specific data is available.
*/
protected selectFirstnamesForBirthdate(birthdate: Date, isMale: boolean): string[];
/**
* Generate a random identity.
*/
generateRandomIdentity(gender?: string | 'random', birthdateOptions?: IBirthdateOptions): Identity;
}
/**
* Identity generator for English language using English word dictionaries.
*/
declare class IdentityGeneratorEn extends IdentityGenerator {
/**
* Get the male first names.
*/
protected getFirstNamesMaleJson(): string[];
/**
* Get the female first names.
*/
protected getFirstNamesFemaleJson(): string[];
/**
* Get the last names.
*/
protected getLastNamesJson(): string[];
}
/**
* Identity generator for Dutch language using Dutch word dictionaries.
*/
declare class IdentityGeneratorNl extends IdentityGenerator {
/**
* Get the male first names.
*/
protected getFirstNamesMaleJson(): string[];
/**
* Get the female first names.
*/
protected getFirstNamesFemaleJson(): string[];
/**
* Get the last names.
*/
protected getLastNamesJson(): string[];
}
/**
* Helper utilities for identity generation that can be used by multiple client applications.
*/
declare class IdentityHelperUtils {
/**
* Normalize a birth date for display.
*/
static normalizeBirthDateForDisplay(birthDate: string | undefined): string;
/**
* Normalize a birth date for database storage.
* Converts any date format to the standard format: "yyyy-MM-dd 00:00:00" (19 characters).
* BirthDate fields do not include time or milliseconds, just date with 00:00:00.
*/
static normalizeBirthDateForDb(input: string | undefined): string;
/**
* Check if a birth date is valid.
*/
static isValidBirthDate(input: string | undefined): boolean;
}
/**
* Generate a username or email prefix.
*/
declare class UsernameEmailGenerator {
private static readonly MIN_LENGTH;
private static readonly MAX_LENGTH;
private readonly symbols;
/**
* Generate a username based on an identity.
*/
generateUsername(identity: Identity): string;
/**
* Generate an email prefix based on an identity.
*/
generateEmailPrefix(identity: Identity): string;
/**
* Sanitize an email prefix.
*/
private sanitizeEmailPrefix;
/**
* Get a random symbol.
*/
private getRandomSymbol;
/**
* Generate a random string.
*/
private generateRandomString;
/**
* Generate a secure random integer between 0 (inclusive) and max (exclusive)
*/
private getSecureRandom;
}
/**
* Represents an age range option for identity generation.
*/
interface IAgeRangeOption {
/**
* The value to store (e.g., "21-25", "random")
*/
value: string;
/**
* The display label (e.g., "21-25", "Random")
*/
label: string;
}
/**
* Gets all available age range options for identity generation.
* @returns Array of age range options
*/
declare function getAvailableAgeRanges(): IAgeRangeOption[];
/**
* Converts an age range string (e.g., "21-25", "30-35", or "random") to birthdate options.
* @param ageRange - The age range string
* @returns An object containing targetYear and yearDeviation, or null if random
*/
declare function convertAgeRangeToBirthdateOptions(ageRange: string): IBirthdateOptions | null;
/**
* Represents a language option for identity generation.
*/
interface ILanguageOption {
/**
* The language code (e.g., "en", "nl", "de")
*/
value: string;
/**
* The display label in the native language (e.g., "English", "Nederlands", "Deutsch")
*/
label: string;
/**
* The flag emoji for the language (e.g., "🇬🇧", "🇳🇱", "🇩🇪")
*/
flag: string;
}
/**
* Gets all available languages for identity generation.
* Display labels are in the native language, with optional flag emoji that clients can choose to display.
* @returns Array of language options
*/
declare function getAvailableLanguages(): ILanguageOption[];
/**
* Creates a new identity generator based on the language.
* Falls back to English if the requested language is not supported.
* @param language - The language to use for generating the identity (e.g. "en", "nl").
* @returns A new identity generator instance.
*/
declare const CreateIdentityGenerator: (language: string) => IdentityGenerator;
/**
* Creates a new username email generator. This is used by the .NET Blazor WASM JSinterop
* as it cannot create instances of classes directly, it has to use a factory method.
* @returns A new username email generator instance.
*/
declare const CreateUsernameEmailGenerator: () => UsernameEmailGenerator;
export { CreateIdentityGenerator, CreateUsernameEmailGenerator, Gender, type IAgeRangeOption, type IBirthdateOptions, type IDecadeFirstnames, type IIdentityGenerator, type ILanguageOption, type Identity, IdentityGenerator, IdentityGeneratorEn, IdentityGeneratorNl, IdentityHelperUtils, UsernameEmailGenerator, convertAgeRangeToBirthdateOptions, getAvailableAgeRanges, getAvailableLanguages };

View File

@@ -197,8 +197,33 @@ declare function getAvailableAgeRanges(): IAgeRangeOption[];
*/
declare function convertAgeRangeToBirthdateOptions(ageRange: string): IBirthdateOptions | null;
/**
* Represents a language option for identity generation.
*/
interface ILanguageOption {
/**
* The language code (e.g., "en", "nl", "de")
*/
value: string;
/**
* The display label in the native language (e.g., "English", "Nederlands", "Deutsch")
*/
label: string;
/**
* The flag emoji for the language (e.g., "🇬🇧", "🇳🇱", "🇩🇪")
*/
flag: string;
}
/**
* Gets all available languages for identity generation.
* Display labels are in the native language, with optional flag emoji that clients can choose to display.
* @returns Array of language options
*/
declare function getAvailableLanguages(): ILanguageOption[];
/**
* Creates a new identity generator based on the language.
* Falls back to English if the requested language is not supported.
* @param language - The language to use for generating the identity (e.g. "en", "nl").
* @returns A new identity generator instance.
*/
@@ -211,4 +236,4 @@ declare const CreateIdentityGenerator: (language: string) => IdentityGenerator;
*/
declare const CreateUsernameEmailGenerator: () => UsernameEmailGenerator;
export { CreateIdentityGenerator, CreateUsernameEmailGenerator, Gender, type IAgeRangeOption, type IBirthdateOptions, type IDecadeFirstnames, type IIdentityGenerator, type Identity, IdentityGenerator, IdentityGeneratorEn, IdentityGeneratorNl, IdentityHelperUtils, UsernameEmailGenerator, convertAgeRangeToBirthdateOptions, getAvailableAgeRanges };
export { CreateIdentityGenerator, CreateUsernameEmailGenerator, Gender, type IAgeRangeOption, type IBirthdateOptions, type IDecadeFirstnames, type IIdentityGenerator, type ILanguageOption, type Identity, IdentityGenerator, IdentityGeneratorEn, IdentityGeneratorNl, IdentityHelperUtils, UsernameEmailGenerator, convertAgeRangeToBirthdateOptions, getAvailableAgeRanges, getAvailableLanguages };

View File

@@ -32,7 +32,8 @@ __export(index_exports, {
IdentityHelperUtils: () => IdentityHelperUtils,
UsernameEmailGenerator: () => UsernameEmailGenerator,
convertAgeRangeToBirthdateOptions: () => convertAgeRangeToBirthdateOptions,
getAvailableAgeRanges: () => getAvailableAgeRanges
getAvailableAgeRanges: () => getAvailableAgeRanges,
getAvailableLanguages: () => getAvailableLanguages
});
module.exports = __toCommonJS(index_exports);
@@ -1995,15 +1996,25 @@ function convertAgeRangeToBirthdateOptions(ageRange) {
return { targetYear, yearDeviation };
}
// src/utils/LanguageProvider.ts
function getAvailableLanguages() {
return [
{ value: "en", label: "English", flag: "\u{1F1EC}\u{1F1E7}" },
{ value: "nl", label: "Nederlands", flag: "\u{1F1F3}\u{1F1F1}" }
];
}
// src/factories/IdentityGeneratorFactory.ts
var CreateIdentityGenerator = (language) => {
switch (language) {
switch (language.toLowerCase()) {
case "en":
return new IdentityGeneratorEn();
case "nl":
return new IdentityGeneratorNl();
default:
console.warn(`Language '${language}' is not supported. Falling back to English.`);
return new IdentityGeneratorEn();
}
throw new Error(`Unsupported language: ${language}`);
};
// src/factories/UsernameEmailGeneratorFactory.ts
@@ -2021,5 +2032,6 @@ var CreateUsernameEmailGenerator = () => {
IdentityHelperUtils,
UsernameEmailGenerator,
convertAgeRangeToBirthdateOptions,
getAvailableAgeRanges
getAvailableAgeRanges,
getAvailableLanguages
});

View File

@@ -1961,15 +1961,25 @@ function convertAgeRangeToBirthdateOptions(ageRange) {
return { targetYear, yearDeviation };
}
// src/utils/LanguageProvider.ts
function getAvailableLanguages() {
return [
{ value: "en", label: "English", flag: "\u{1F1EC}\u{1F1E7}" },
{ value: "nl", label: "Nederlands", flag: "\u{1F1F3}\u{1F1F1}" }
];
}
// src/factories/IdentityGeneratorFactory.ts
var CreateIdentityGenerator = (language) => {
switch (language) {
switch (language.toLowerCase()) {
case "en":
return new IdentityGeneratorEn();
case "nl":
return new IdentityGeneratorNl();
default:
console.warn(`Language '${language}' is not supported. Falling back to English.`);
return new IdentityGeneratorEn();
}
throw new Error(`Unsupported language: ${language}`);
};
// src/factories/UsernameEmailGeneratorFactory.ts
@@ -1986,5 +1996,6 @@ export {
IdentityHelperUtils,
UsernameEmailGenerator,
convertAgeRangeToBirthdateOptions,
getAvailableAgeRanges
getAvailableAgeRanges,
getAvailableLanguages
};

View File

@@ -0,0 +1,239 @@
declare enum Gender {
Male = "Male",
Female = "Female",
Other = "Other"
}
/**
* Identity.
*/
type Identity = {
firstName: string;
lastName: string;
gender: Gender;
birthDate: Date;
emailPrefix: string;
nickName: string;
};
/**
* Options for birthdate generation.
*/
interface IBirthdateOptions {
/**
* The target year for the birthdate (e.g., 1990).
*/
targetYear: number;
/**
* The random deviation in years (e.g., 5 means ±5 years from targetYear).
* If 0, a random date within the target year will be chosen.
*/
yearDeviation: number;
}
interface IIdentityGenerator {
generateRandomIdentity(gender?: string | 'random', birthdateOptions?: IBirthdateOptions): Identity;
}
/**
* Dictionary of firstnames organized by decade range.
*/
interface IDecadeFirstnames {
startYear: number;
endYear: number;
names: string[];
}
/**
* Base identity generator.
*/
declare abstract class IdentityGenerator implements IIdentityGenerator {
protected firstNamesMale: string[];
protected firstNamesFemale: string[];
protected lastNames: string[];
private readonly random;
/**
* Constructor.
*/
constructor();
protected abstract getFirstNamesMaleJson(): string[];
protected abstract getFirstNamesFemaleJson(): string[];
protected abstract getLastNamesJson(): string[];
/**
* Get decade-based male first names. Override this to provide age-specific names.
* If not overridden, returns an empty array and falls back to generic names.
*/
protected getFirstNamesMaleByDecade(): IDecadeFirstnames[];
/**
* Get decade-based female first names. Override this to provide age-specific names.
* If not overridden, returns an empty array and falls back to generic names.
*/
protected getFirstNamesFemaleByDecade(): IDecadeFirstnames[];
/**
* Generate a random date of birth.
* @param birthdateOptions Optional birthdate configuration
*/
protected generateRandomDateOfBirth(birthdateOptions?: IBirthdateOptions): Date;
/**
* Select appropriate firstnames based on birthdate.
* Falls back to generic names if no decade-specific data is available.
*/
protected selectFirstnamesForBirthdate(birthdate: Date, isMale: boolean): string[];
/**
* Generate a random identity.
*/
generateRandomIdentity(gender?: string | 'random', birthdateOptions?: IBirthdateOptions): Identity;
}
/**
* Identity generator for English language using English word dictionaries.
*/
declare class IdentityGeneratorEn extends IdentityGenerator {
/**
* Get the male first names.
*/
protected getFirstNamesMaleJson(): string[];
/**
* Get the female first names.
*/
protected getFirstNamesFemaleJson(): string[];
/**
* Get the last names.
*/
protected getLastNamesJson(): string[];
}
/**
* Identity generator for Dutch language using Dutch word dictionaries.
*/
declare class IdentityGeneratorNl extends IdentityGenerator {
/**
* Get the male first names.
*/
protected getFirstNamesMaleJson(): string[];
/**
* Get the female first names.
*/
protected getFirstNamesFemaleJson(): string[];
/**
* Get the last names.
*/
protected getLastNamesJson(): string[];
}
/**
* Helper utilities for identity generation that can be used by multiple client applications.
*/
declare class IdentityHelperUtils {
/**
* Normalize a birth date for display.
*/
static normalizeBirthDateForDisplay(birthDate: string | undefined): string;
/**
* Normalize a birth date for database storage.
* Converts any date format to the standard format: "yyyy-MM-dd 00:00:00" (19 characters).
* BirthDate fields do not include time or milliseconds, just date with 00:00:00.
*/
static normalizeBirthDateForDb(input: string | undefined): string;
/**
* Check if a birth date is valid.
*/
static isValidBirthDate(input: string | undefined): boolean;
}
/**
* Generate a username or email prefix.
*/
declare class UsernameEmailGenerator {
private static readonly MIN_LENGTH;
private static readonly MAX_LENGTH;
private readonly symbols;
/**
* Generate a username based on an identity.
*/
generateUsername(identity: Identity): string;
/**
* Generate an email prefix based on an identity.
*/
generateEmailPrefix(identity: Identity): string;
/**
* Sanitize an email prefix.
*/
private sanitizeEmailPrefix;
/**
* Get a random symbol.
*/
private getRandomSymbol;
/**
* Generate a random string.
*/
private generateRandomString;
/**
* Generate a secure random integer between 0 (inclusive) and max (exclusive)
*/
private getSecureRandom;
}
/**
* Represents an age range option for identity generation.
*/
interface IAgeRangeOption {
/**
* The value to store (e.g., "21-25", "random")
*/
value: string;
/**
* The display label (e.g., "21-25", "Random")
*/
label: string;
}
/**
* Gets all available age range options for identity generation.
* @returns Array of age range options
*/
declare function getAvailableAgeRanges(): IAgeRangeOption[];
/**
* Converts an age range string (e.g., "21-25", "30-35", or "random") to birthdate options.
* @param ageRange - The age range string
* @returns An object containing targetYear and yearDeviation, or null if random
*/
declare function convertAgeRangeToBirthdateOptions(ageRange: string): IBirthdateOptions | null;
/**
* Represents a language option for identity generation.
*/
interface ILanguageOption {
/**
* The language code (e.g., "en", "nl", "de")
*/
value: string;
/**
* The display label in the native language (e.g., "English", "Nederlands", "Deutsch")
*/
label: string;
/**
* The flag emoji for the language (e.g., "🇬🇧", "🇳🇱", "🇩🇪")
*/
flag: string;
}
/**
* Gets all available languages for identity generation.
* Display labels are in the native language, with optional flag emoji that clients can choose to display.
* @returns Array of language options
*/
declare function getAvailableLanguages(): ILanguageOption[];
/**
* Creates a new identity generator based on the language.
* Falls back to English if the requested language is not supported.
* @param language - The language to use for generating the identity (e.g. "en", "nl").
* @returns A new identity generator instance.
*/
declare const CreateIdentityGenerator: (language: string) => IdentityGenerator;
/**
* Creates a new username email generator. This is used by the .NET Blazor WASM JSinterop
* as it cannot create instances of classes directly, it has to use a factory method.
* @returns A new username email generator instance.
*/
declare const CreateUsernameEmailGenerator: () => UsernameEmailGenerator;
export { CreateIdentityGenerator, CreateUsernameEmailGenerator, Gender, type IAgeRangeOption, type IBirthdateOptions, type IDecadeFirstnames, type IIdentityGenerator, type ILanguageOption, type Identity, IdentityGenerator, IdentityGeneratorEn, IdentityGeneratorNl, IdentityHelperUtils, UsernameEmailGenerator, convertAgeRangeToBirthdateOptions, getAvailableAgeRanges, getAvailableLanguages };

View File

@@ -197,8 +197,33 @@ declare function getAvailableAgeRanges(): IAgeRangeOption[];
*/
declare function convertAgeRangeToBirthdateOptions(ageRange: string): IBirthdateOptions | null;
/**
* Represents a language option for identity generation.
*/
interface ILanguageOption {
/**
* The language code (e.g., "en", "nl", "de")
*/
value: string;
/**
* The display label in the native language (e.g., "English", "Nederlands", "Deutsch")
*/
label: string;
/**
* The flag emoji for the language (e.g., "🇬🇧", "🇳🇱", "🇩🇪")
*/
flag: string;
}
/**
* Gets all available languages for identity generation.
* Display labels are in the native language, with optional flag emoji that clients can choose to display.
* @returns Array of language options
*/
declare function getAvailableLanguages(): ILanguageOption[];
/**
* Creates a new identity generator based on the language.
* Falls back to English if the requested language is not supported.
* @param language - The language to use for generating the identity (e.g. "en", "nl").
* @returns A new identity generator instance.
*/
@@ -211,4 +236,4 @@ declare const CreateIdentityGenerator: (language: string) => IdentityGenerator;
*/
declare const CreateUsernameEmailGenerator: () => UsernameEmailGenerator;
export { CreateIdentityGenerator, CreateUsernameEmailGenerator, Gender, type IAgeRangeOption, type IBirthdateOptions, type IDecadeFirstnames, type IIdentityGenerator, type Identity, IdentityGenerator, IdentityGeneratorEn, IdentityGeneratorNl, IdentityHelperUtils, UsernameEmailGenerator, convertAgeRangeToBirthdateOptions, getAvailableAgeRanges };
export { CreateIdentityGenerator, CreateUsernameEmailGenerator, Gender, type IAgeRangeOption, type IBirthdateOptions, type IDecadeFirstnames, type IIdentityGenerator, type ILanguageOption, type Identity, IdentityGenerator, IdentityGeneratorEn, IdentityGeneratorNl, IdentityHelperUtils, UsernameEmailGenerator, convertAgeRangeToBirthdateOptions, getAvailableAgeRanges, getAvailableLanguages };

View File

@@ -32,7 +32,8 @@ __export(index_exports, {
IdentityHelperUtils: () => IdentityHelperUtils,
UsernameEmailGenerator: () => UsernameEmailGenerator,
convertAgeRangeToBirthdateOptions: () => convertAgeRangeToBirthdateOptions,
getAvailableAgeRanges: () => getAvailableAgeRanges
getAvailableAgeRanges: () => getAvailableAgeRanges,
getAvailableLanguages: () => getAvailableLanguages
});
module.exports = __toCommonJS(index_exports);
@@ -1995,15 +1996,25 @@ function convertAgeRangeToBirthdateOptions(ageRange) {
return { targetYear, yearDeviation };
}
// src/utils/LanguageProvider.ts
function getAvailableLanguages() {
return [
{ value: "en", label: "English", flag: "\u{1F1EC}\u{1F1E7}" },
{ value: "nl", label: "Nederlands", flag: "\u{1F1F3}\u{1F1F1}" }
];
}
// src/factories/IdentityGeneratorFactory.ts
var CreateIdentityGenerator = (language) => {
switch (language) {
switch (language.toLowerCase()) {
case "en":
return new IdentityGeneratorEn();
case "nl":
return new IdentityGeneratorNl();
default:
console.warn(`Language '${language}' is not supported. Falling back to English.`);
return new IdentityGeneratorEn();
}
throw new Error(`Unsupported language: ${language}`);
};
// src/factories/UsernameEmailGeneratorFactory.ts
@@ -2021,5 +2032,6 @@ var CreateUsernameEmailGenerator = () => {
IdentityHelperUtils,
UsernameEmailGenerator,
convertAgeRangeToBirthdateOptions,
getAvailableAgeRanges
getAvailableAgeRanges,
getAvailableLanguages
});

View File

@@ -1961,15 +1961,25 @@ function convertAgeRangeToBirthdateOptions(ageRange) {
return { targetYear, yearDeviation };
}
// src/utils/LanguageProvider.ts
function getAvailableLanguages() {
return [
{ value: "en", label: "English", flag: "\u{1F1EC}\u{1F1E7}" },
{ value: "nl", label: "Nederlands", flag: "\u{1F1F3}\u{1F1F1}" }
];
}
// src/factories/IdentityGeneratorFactory.ts
var CreateIdentityGenerator = (language) => {
switch (language) {
switch (language.toLowerCase()) {
case "en":
return new IdentityGeneratorEn();
case "nl":
return new IdentityGeneratorNl();
default:
console.warn(`Language '${language}' is not supported. Falling back to English.`);
return new IdentityGeneratorEn();
}
throw new Error(`Unsupported language: ${language}`);
};
// src/factories/UsernameEmailGeneratorFactory.ts
@@ -1986,5 +1996,6 @@ export {
IdentityHelperUtils,
UsernameEmailGenerator,
convertAgeRangeToBirthdateOptions,
getAvailableAgeRanges
getAvailableAgeRanges,
getAvailableLanguages
};

View File

@@ -74,9 +74,10 @@
<div class="mb-4">
<label for="defaultIdentityLanguage" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">@Localizer["AliasGenerationLanguageLabel"]</label>
<select @bind="DefaultIdentityLanguage" @bind:after="UpdateDefaultIdentityLanguage" id="defaultIdentityLanguage" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500">
<option value="en">@Localizer["EnglishOption"]</option>
<option value="nl">@Localizer["DutchOption"]</option>
<option value="de">@Localizer["GermanOption"]</option>
@foreach (var language in AvailableLanguages)
{
<option value="@language.Value">@language.Flag @language.Label</option>
}
</select>
<span class="block text-sm font-normal text-gray-500 truncate dark:text-gray-400">
@Localizer["AliasGenerationLanguageDescription"]
@@ -154,6 +155,7 @@
private string DefaultIdentityAgeRange { get; set; } = string.Empty;
private string AppLanguage { get; set; } = string.Empty;
private int ClipboardClearSeconds { get; set; }
private List<LanguageOption> AvailableLanguages { get; set; } = new();
private List<AgeRangeOption> AvailableAgeRanges { get; set; } = new();
/// <inheritdoc />
@@ -162,8 +164,9 @@
await base.OnInitializedAsync();
BreadcrumbItems.Add(new BreadcrumbItem { DisplayName = Localizer["BreadcrumbTitle"] });
// Load available age ranges from JavaScript utility
AvailableAgeRanges = await JsInteropService.GetAvailableAgeRangesAsync();
// Load available languages and age ranges from JavaScript utility
AvailableLanguages = await JsInteropService.GetAvailableIdentityGeneratorLanguagesAsync();
AvailableAgeRanges = await JsInteropService.GetAvailableIdentityGeneratorAgeRangesAsync();
DefaultEmailDomain = DbService.Settings.DefaultEmailDomain;
if (DefaultEmailDomain == string.Empty || Config.HiddenPrivateEmailDomains.Contains(DefaultEmailDomain))

View File

@@ -85,18 +85,6 @@
<value>Set the default language that will be used when generating new identities.</value>
<comment>Description for alias generation language setting</comment>
</data>
<data name="EnglishOption">
<value>English</value>
<comment>English language option</comment>
</data>
<data name="DutchOption">
<value>Dutch</value>
<comment>Dutch language option</comment>
</data>
<data name="GermanOption">
<value>German</value>
<comment>German language option</comment>
</data>
<data name="AliasGenerationGenderLabel">
<value>Gender</value>
<comment>Label for alias generation gender setting</comment>

View File

@@ -360,11 +360,34 @@ public sealed class JsInteropService(IJSRuntime jsRuntime)
return await jsRuntime.InvokeAsync<byte[]>("cryptoInterop.decryptBytes", base64Ciphertext, encryptionKey);
}
/// <summary>
/// Gets all available languages for identity generation.
/// </summary>
/// <returns>Array of language options.</returns>
public async Task<List<LanguageOption>> GetAvailableIdentityGeneratorLanguagesAsync()
{
try
{
if (_identityGeneratorModule == null)
{
await InitializeAsync();
}
var result = await _identityGeneratorModule!.InvokeAsync<List<LanguageOption>>("getAvailableLanguages");
return result ?? new List<LanguageOption>();
}
catch (JSException ex)
{
await Console.Error.WriteLineAsync($"JavaScript error getting available languages: {ex.Message}");
return new List<LanguageOption>();
}
}
/// <summary>
/// Gets all available age range options from the shared JavaScript utility.
/// </summary>
/// <returns>Array of age range options.</returns>
public async Task<List<AgeRangeOption>> GetAvailableAgeRangesAsync()
public async Task<List<AgeRangeOption>> GetAvailableIdentityGeneratorAgeRangesAsync()
{
try
{

View File

@@ -0,0 +1,29 @@
//-----------------------------------------------------------------------
// <copyright file="LanguageOption.cs" company="aliasvault">
// Copyright (c) aliasvault. All rights reserved.
// Licensed under the AGPLv3 license. See LICENSE.md file in the project root for full license information.
// </copyright>
//-----------------------------------------------------------------------
namespace AliasVault.Client.Services.JsInterop.Models;
/// <summary>
/// Represents a language option for identity generation.
/// </summary>
public sealed class LanguageOption
{
/// <summary>
/// Gets or sets the language code (e.g., "en", "nl", "de").
/// </summary>
public string Value { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the display label in the native language (e.g., "English", "Nederlands", "Deutsch").
/// </summary>
public string Label { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the flag emoji for the language (e.g., "🇬🇧", "🇳🇱", "🇩🇪").
/// </summary>
public string Flag { get; set; } = string.Empty;
}

View File

@@ -0,0 +1,239 @@
declare enum Gender {
Male = "Male",
Female = "Female",
Other = "Other"
}
/**
* Identity.
*/
type Identity = {
firstName: string;
lastName: string;
gender: Gender;
birthDate: Date;
emailPrefix: string;
nickName: string;
};
/**
* Options for birthdate generation.
*/
interface IBirthdateOptions {
/**
* The target year for the birthdate (e.g., 1990).
*/
targetYear: number;
/**
* The random deviation in years (e.g., 5 means ±5 years from targetYear).
* If 0, a random date within the target year will be chosen.
*/
yearDeviation: number;
}
interface IIdentityGenerator {
generateRandomIdentity(gender?: string | 'random', birthdateOptions?: IBirthdateOptions): Identity;
}
/**
* Dictionary of firstnames organized by decade range.
*/
interface IDecadeFirstnames {
startYear: number;
endYear: number;
names: string[];
}
/**
* Base identity generator.
*/
declare abstract class IdentityGenerator implements IIdentityGenerator {
protected firstNamesMale: string[];
protected firstNamesFemale: string[];
protected lastNames: string[];
private readonly random;
/**
* Constructor.
*/
constructor();
protected abstract getFirstNamesMaleJson(): string[];
protected abstract getFirstNamesFemaleJson(): string[];
protected abstract getLastNamesJson(): string[];
/**
* Get decade-based male first names. Override this to provide age-specific names.
* If not overridden, returns an empty array and falls back to generic names.
*/
protected getFirstNamesMaleByDecade(): IDecadeFirstnames[];
/**
* Get decade-based female first names. Override this to provide age-specific names.
* If not overridden, returns an empty array and falls back to generic names.
*/
protected getFirstNamesFemaleByDecade(): IDecadeFirstnames[];
/**
* Generate a random date of birth.
* @param birthdateOptions Optional birthdate configuration
*/
protected generateRandomDateOfBirth(birthdateOptions?: IBirthdateOptions): Date;
/**
* Select appropriate firstnames based on birthdate.
* Falls back to generic names if no decade-specific data is available.
*/
protected selectFirstnamesForBirthdate(birthdate: Date, isMale: boolean): string[];
/**
* Generate a random identity.
*/
generateRandomIdentity(gender?: string | 'random', birthdateOptions?: IBirthdateOptions): Identity;
}
/**
* Identity generator for English language using English word dictionaries.
*/
declare class IdentityGeneratorEn extends IdentityGenerator {
/**
* Get the male first names.
*/
protected getFirstNamesMaleJson(): string[];
/**
* Get the female first names.
*/
protected getFirstNamesFemaleJson(): string[];
/**
* Get the last names.
*/
protected getLastNamesJson(): string[];
}
/**
* Identity generator for Dutch language using Dutch word dictionaries.
*/
declare class IdentityGeneratorNl extends IdentityGenerator {
/**
* Get the male first names.
*/
protected getFirstNamesMaleJson(): string[];
/**
* Get the female first names.
*/
protected getFirstNamesFemaleJson(): string[];
/**
* Get the last names.
*/
protected getLastNamesJson(): string[];
}
/**
* Helper utilities for identity generation that can be used by multiple client applications.
*/
declare class IdentityHelperUtils {
/**
* Normalize a birth date for display.
*/
static normalizeBirthDateForDisplay(birthDate: string | undefined): string;
/**
* Normalize a birth date for database storage.
* Converts any date format to the standard format: "yyyy-MM-dd 00:00:00" (19 characters).
* BirthDate fields do not include time or milliseconds, just date with 00:00:00.
*/
static normalizeBirthDateForDb(input: string | undefined): string;
/**
* Check if a birth date is valid.
*/
static isValidBirthDate(input: string | undefined): boolean;
}
/**
* Generate a username or email prefix.
*/
declare class UsernameEmailGenerator {
private static readonly MIN_LENGTH;
private static readonly MAX_LENGTH;
private readonly symbols;
/**
* Generate a username based on an identity.
*/
generateUsername(identity: Identity): string;
/**
* Generate an email prefix based on an identity.
*/
generateEmailPrefix(identity: Identity): string;
/**
* Sanitize an email prefix.
*/
private sanitizeEmailPrefix;
/**
* Get a random symbol.
*/
private getRandomSymbol;
/**
* Generate a random string.
*/
private generateRandomString;
/**
* Generate a secure random integer between 0 (inclusive) and max (exclusive)
*/
private getSecureRandom;
}
/**
* Represents an age range option for identity generation.
*/
interface IAgeRangeOption {
/**
* The value to store (e.g., "21-25", "random")
*/
value: string;
/**
* The display label (e.g., "21-25", "Random")
*/
label: string;
}
/**
* Gets all available age range options for identity generation.
* @returns Array of age range options
*/
declare function getAvailableAgeRanges(): IAgeRangeOption[];
/**
* Converts an age range string (e.g., "21-25", "30-35", or "random") to birthdate options.
* @param ageRange - The age range string
* @returns An object containing targetYear and yearDeviation, or null if random
*/
declare function convertAgeRangeToBirthdateOptions(ageRange: string): IBirthdateOptions | null;
/**
* Represents a language option for identity generation.
*/
interface ILanguageOption {
/**
* The language code (e.g., "en", "nl", "de")
*/
value: string;
/**
* The display label in the native language (e.g., "English", "Nederlands", "Deutsch")
*/
label: string;
/**
* The flag emoji for the language (e.g., "🇬🇧", "🇳🇱", "🇩🇪")
*/
flag: string;
}
/**
* Gets all available languages for identity generation.
* Display labels are in the native language, with optional flag emoji that clients can choose to display.
* @returns Array of language options
*/
declare function getAvailableLanguages(): ILanguageOption[];
/**
* Creates a new identity generator based on the language.
* Falls back to English if the requested language is not supported.
* @param language - The language to use for generating the identity (e.g. "en", "nl").
* @returns A new identity generator instance.
*/
declare const CreateIdentityGenerator: (language: string) => IdentityGenerator;
/**
* Creates a new username email generator. This is used by the .NET Blazor WASM JSinterop
* as it cannot create instances of classes directly, it has to use a factory method.
* @returns A new username email generator instance.
*/
declare const CreateUsernameEmailGenerator: () => UsernameEmailGenerator;
export { CreateIdentityGenerator, CreateUsernameEmailGenerator, Gender, type IAgeRangeOption, type IBirthdateOptions, type IDecadeFirstnames, type IIdentityGenerator, type ILanguageOption, type Identity, IdentityGenerator, IdentityGeneratorEn, IdentityGeneratorNl, IdentityHelperUtils, UsernameEmailGenerator, convertAgeRangeToBirthdateOptions, getAvailableAgeRanges, getAvailableLanguages };

View File

@@ -197,8 +197,33 @@ declare function getAvailableAgeRanges(): IAgeRangeOption[];
*/
declare function convertAgeRangeToBirthdateOptions(ageRange: string): IBirthdateOptions | null;
/**
* Represents a language option for identity generation.
*/
interface ILanguageOption {
/**
* The language code (e.g., "en", "nl", "de")
*/
value: string;
/**
* The display label in the native language (e.g., "English", "Nederlands", "Deutsch")
*/
label: string;
/**
* The flag emoji for the language (e.g., "🇬🇧", "🇳🇱", "🇩🇪")
*/
flag: string;
}
/**
* Gets all available languages for identity generation.
* Display labels are in the native language, with optional flag emoji that clients can choose to display.
* @returns Array of language options
*/
declare function getAvailableLanguages(): ILanguageOption[];
/**
* Creates a new identity generator based on the language.
* Falls back to English if the requested language is not supported.
* @param language - The language to use for generating the identity (e.g. "en", "nl").
* @returns A new identity generator instance.
*/
@@ -211,4 +236,4 @@ declare const CreateIdentityGenerator: (language: string) => IdentityGenerator;
*/
declare const CreateUsernameEmailGenerator: () => UsernameEmailGenerator;
export { CreateIdentityGenerator, CreateUsernameEmailGenerator, Gender, type IAgeRangeOption, type IBirthdateOptions, type IDecadeFirstnames, type IIdentityGenerator, type Identity, IdentityGenerator, IdentityGeneratorEn, IdentityGeneratorNl, IdentityHelperUtils, UsernameEmailGenerator, convertAgeRangeToBirthdateOptions, getAvailableAgeRanges };
export { CreateIdentityGenerator, CreateUsernameEmailGenerator, Gender, type IAgeRangeOption, type IBirthdateOptions, type IDecadeFirstnames, type IIdentityGenerator, type ILanguageOption, type Identity, IdentityGenerator, IdentityGeneratorEn, IdentityGeneratorNl, IdentityHelperUtils, UsernameEmailGenerator, convertAgeRangeToBirthdateOptions, getAvailableAgeRanges, getAvailableLanguages };

View File

@@ -32,7 +32,8 @@ __export(index_exports, {
IdentityHelperUtils: () => IdentityHelperUtils,
UsernameEmailGenerator: () => UsernameEmailGenerator,
convertAgeRangeToBirthdateOptions: () => convertAgeRangeToBirthdateOptions,
getAvailableAgeRanges: () => getAvailableAgeRanges
getAvailableAgeRanges: () => getAvailableAgeRanges,
getAvailableLanguages: () => getAvailableLanguages
});
module.exports = __toCommonJS(index_exports);
@@ -1995,15 +1996,25 @@ function convertAgeRangeToBirthdateOptions(ageRange) {
return { targetYear, yearDeviation };
}
// src/utils/LanguageProvider.ts
function getAvailableLanguages() {
return [
{ value: "en", label: "English", flag: "\u{1F1EC}\u{1F1E7}" },
{ value: "nl", label: "Nederlands", flag: "\u{1F1F3}\u{1F1F1}" }
];
}
// src/factories/IdentityGeneratorFactory.ts
var CreateIdentityGenerator = (language) => {
switch (language) {
switch (language.toLowerCase()) {
case "en":
return new IdentityGeneratorEn();
case "nl":
return new IdentityGeneratorNl();
default:
console.warn(`Language '${language}' is not supported. Falling back to English.`);
return new IdentityGeneratorEn();
}
throw new Error(`Unsupported language: ${language}`);
};
// src/factories/UsernameEmailGeneratorFactory.ts
@@ -2021,5 +2032,6 @@ var CreateUsernameEmailGenerator = () => {
IdentityHelperUtils,
UsernameEmailGenerator,
convertAgeRangeToBirthdateOptions,
getAvailableAgeRanges
getAvailableAgeRanges,
getAvailableLanguages
});

View File

@@ -1961,15 +1961,25 @@ function convertAgeRangeToBirthdateOptions(ageRange) {
return { targetYear, yearDeviation };
}
// src/utils/LanguageProvider.ts
function getAvailableLanguages() {
return [
{ value: "en", label: "English", flag: "\u{1F1EC}\u{1F1E7}" },
{ value: "nl", label: "Nederlands", flag: "\u{1F1F3}\u{1F1F1}" }
];
}
// src/factories/IdentityGeneratorFactory.ts
var CreateIdentityGenerator = (language) => {
switch (language) {
switch (language.toLowerCase()) {
case "en":
return new IdentityGeneratorEn();
case "nl":
return new IdentityGeneratorNl();
default:
console.warn(`Language '${language}' is not supported. Falling back to English.`);
return new IdentityGeneratorEn();
}
throw new Error(`Unsupported language: ${language}`);
};
// src/factories/UsernameEmailGeneratorFactory.ts
@@ -1986,5 +1996,6 @@ export {
IdentityHelperUtils,
UsernameEmailGenerator,
convertAgeRangeToBirthdateOptions,
getAvailableAgeRanges
getAvailableAgeRanges,
getAvailableLanguages
};

View File

@@ -4,16 +4,19 @@ import { IdentityGeneratorNl } from "src/implementations/IdentityGeneratorNl";
/**
* Creates a new identity generator based on the language.
* Falls back to English if the requested language is not supported.
* @param language - The language to use for generating the identity (e.g. "en", "nl").
* @returns A new identity generator instance.
*/
export const CreateIdentityGenerator = (language: string): IdentityGenerator => {
switch (language) {
switch (language.toLowerCase()) {
case 'en':
return new IdentityGeneratorEn();
case 'nl':
return new IdentityGeneratorNl();
default:
// Fallback to English for unsupported languages
console.warn(`Language '${language}' is not supported. Falling back to English.`);
return new IdentityGeneratorEn();
}
throw new Error(`Unsupported language: ${language}`);
};

View File

@@ -7,5 +7,6 @@ export * from './interfaces/IIdentityGenerator';
export * from './utils/IdentityHelperUtils';
export * from './utils/UsernameEmailGenerator';
export * from './utils/AgeRangeConverter';
export * from './utils/LanguageProvider';
export * from './factories/IdentityGeneratorFactory';
export * from './factories/UsernameEmailGeneratorFactory';

View File

@@ -0,0 +1,31 @@
/**
* Represents a language option for identity generation.
*/
export interface ILanguageOption {
/**
* The language code (e.g., "en", "nl", "de")
*/
value: string;
/**
* The display label in the native language (e.g., "English", "Nederlands", "Deutsch")
*/
label: string;
/**
* The flag emoji for the language (e.g., "🇬🇧", "🇳🇱", "🇩🇪")
*/
flag: string;
}
/**
* Gets all available languages for identity generation.
* Display labels are in the native language, with optional flag emoji that clients can choose to display.
* @returns Array of language options
*/
export function getAvailableLanguages(): ILanguageOption[] {
return [
{ value: 'en', label: 'English', flag: '🇬🇧' },
{ value: 'nl', label: 'Nederlands', flag: '🇳🇱' }
];
}