Skip to main content

Estonian Cultural Context & Localization

Estonian cultural context differs from Western defaults, requiring specific handling for occasions, budgets, and gift appropriateness.

Estonian Cultural Calendar

Location: language.ts:77-132

Major Estonian Occasions

const ESTONIAN_OCCASIONS = [
{
name: 'Jaanipäev', // Midsummer Day (MAJOR Estonian holiday)
date: '06-23',
typicalBudget: { min: 15, max: 40 },
keywords: ['jaanipäev', 'jaani', 'jaanikingitus']
},
{
name: 'Kadripäev', // St. Catherine's Day
date: '11-25',
typicalBudget: { min: 10, max: 25 }
},
{
name: 'Mardipäev', // St. Martin's Day
date: '11-10',
typicalBudget: { min: 10, max: 25 }
},
{
name: 'Isadepäev', // Father's Day
date: '11-14', // NOTE: Different from US!
typicalBudget: { min: 20, max: 60 }
},
{
name: 'Emadepäev', // Mother's Day
date: '05-09', // NOTE: Fixed date, not floating Sunday
typicalBudget: { min: 20, max: 60 }
},
{
name: 'Valentinipäev', // Valentine's / Friend's Day
date: '02-14',
typicalBudget: { min: 15, max: 50 }
},
{
name: 'Naistepäev', // Women's Day (ex-Soviet tradition)
date: '03-08',
typicalBudget: { min: 15, max: 40 }
},
{
name: 'Jõulud', // Christmas
date: '12-24',
typicalBudget: { min: 25, max: 80 }
}
];

Budget Inference

static getBudgetHintByOccasion(occasion: string): BudgetRange | null {
const normalizedOccasion = occasion.toLowerCase().trim();

for (const estonianOccasion of ESTONIAN_OCCASIONS) {
const matched = estonianOccasion.keywords.some(keyword =>
normalizedOccasion.includes(keyword)
);

if (matched) {
return {
min: estonianOccasion.typicalBudget.min,
max: estonianOccasion.typicalBudget.max,
hint: `${estonianOccasion.name} kingitus`
};
}
}

return null;
}

Cultural Filtering Rules

Location: language.ts:51-72

Age and Gender Appropriateness

const CULTURAL_RULES = {
// Elderly recipients (60+) should not receive:
elderlyForbidden: [
'mänguasjad', 'beebi', 'laste', 'nukkude',
'gaming', 'videomängud', 'baby', 'toys', 'kids'
],

// Child recipients (0-12) should not receive:
childForbidden: [
'alkohol', 'vein', 'spirits', 'alcohol', 'wine', 'beer', 'õlu'
],

// Teen recipients (13-19) should not receive:
teenForbidden: [
'beebi', 'baby', 'väikelaste', 'toddler'
]
};

Application

static filterByAge(products: Product[], ageGroup: string): Product[] {
if (ageGroup === 'elderly') {
return products.filter(p =>
!rules.elderlyForbidden.some(forbidden =>
p.category.includes(forbidden)
)
);
}
// ... similar for child, teen
}

Estonian Product Boost

Location: language.ts:420-456

Boosting Strategy

static boostEstonianProducts(products: Product[], language: string): Product[] {
if (language !== 'et') return products;

return products.map(product => {
let boost = 1.0;

// Estonian authors: +15%
const authors = product.authors?.toString().toLowerCase() || '';
if (authors.match(/\b(eesti|estonian)\b/i)) {
boost *= 1.15;
}

// "Eesti" in category: +15%
const category = product.csv_category?.toString() || '';
if (category.includes('Eesti')) {
boost *= 1.15;
}

// Estonian publishers: +10%
if (this.isEstonianPublisher(product)) {
boost *= 1.1;
}

return { ...product, score: product.score * boost };
});
}

Estonian Publishers

const ESTONIAN_PUBLISHERS = [
'varrak', // Major Estonian publisher
'tänapäev', // Contemporary literature
'pegasus', // Children's books
'eesti raamat', // Estonian book
'kunst', // Art publisher
'avita', // Literary publisher
'postimees', // Newspaper/books
'kirjastus' // Generic "publisher"
];

Impact:

  • Estonian author books ranked 15% higher
  • Estonian publishers get 10% boost
  • Results feel more locally relevant

Occasion Synonym Normalization

Location: language.ts:204-218

const OCCASION_SYNONYM_PATTERNS = [
{ pattern: /\b(birthday|b-day)\b/i, canonical: 'sünnipäev' },
{ pattern: /\b(mother'?s day|emadepäev)\b/i, canonical: 'emadepäev' },
{ pattern: /\b(father'?s day|isadepäev)\b/i, canonical: 'isadepäev' },
{ pattern: /\b(valentine'?s day|sõbrapäev)\b/i, canonical: 'valentinipäev' },
{ pattern: /\b(wedding|pulm)\b/i, canonical: 'pulm' }
];

static normalizeOccasion(occasion: string): string {
const lower = occasion.toLowerCase();

for (const { pattern, canonical } of OCCASION_SYNONYM_PATTERNS) {
if (pattern.test(lower)) {
return canonical;
}
}

return occasion;
}

Benefits:

  • Consistent occasion handling
  • Cross-language support
  • Budget inference works for both languages