feat(workspace): refine career workflows

Make job/CV comparisons language-aware and filter recruitment noise. Improve responsive career navigation, shared spacing, dashboard priorities, settings, localized workspace controls, and portable browser tests.
This commit is contained in:
cesnimda
2026-08-29 16:44:44 +02:00
parent 4d4af47651
commit 9edcbfc5de
29 changed files with 827 additions and 236 deletions
@@ -51,7 +51,11 @@ public sealed record CareerMatchDto(
IReadOnlyList<string> Suggestions,
int AiSuggestionCount,
bool HasSelectedCv = false,
string? SelectedCvName = null);
string? SelectedCvName = null,
string JobLanguage = "en",
string? CvLanguage = null,
bool LanguageMismatch = false,
bool UsedTranslatedJobDescription = false);
public interface IApplicationIntelligenceService
{
@@ -259,7 +263,24 @@ public sealed class ApplicationIntelligenceService : IApplicationIntelligenceSer
["Skills"] = skillsText,
};
var result = _match.Evaluate(job.JobTitle, job.Description ?? string.Empty, sections);
var cvCorpus = string.Join("\n", sections.Values);
var jobLanguage = NormalizeMatchLanguage(job.DescriptionLanguage, job.Description);
var cvLanguage = NormalizeMatchLanguage(settings.Language, cvCorpus);
var languageMismatch = !string.Equals(jobLanguage, cvLanguage, StringComparison.OrdinalIgnoreCase);
// Imported Norwegian adverts may already carry a trusted English translation. When the
// explicitly linked CV is English, compare against that saved translation instead of
// penalising equivalent wording in different languages. This endpoint remains read-only:
// it never starts a translation request or mutates either source document.
var useTranslatedJobDescription = languageMismatch
&& jobLanguage == "nb"
&& cvLanguage == "en"
&& !string.IsNullOrWhiteSpace(job.TranslatedDescription);
var matchDescription = useTranslatedJobDescription
? job.TranslatedDescription!
: job.Description ?? string.Empty;
var result = _match.Evaluate(job.JobTitle, matchDescription, sections);
var relevantExperience = experiences
.Select(e => new { Entry = e, Override = Override(settings, e.ItemKey) })
@@ -297,7 +318,11 @@ public sealed class ApplicationIntelligenceService : IApplicationIntelligenceSer
Suggestions: Suggestions(result, relevantExperience.Count),
AiSuggestionCount: aiCount,
HasSelectedCv: true,
SelectedCvName: attached.Name);
SelectedCvName: attached.Name,
JobLanguage: jobLanguage,
CvLanguage: cvLanguage,
LanguageMismatch: languageMismatch,
UsedTranslatedJobDescription: useTranslatedJobDescription);
}
// Suggestions describe what the USER could change. They never edit anything themselves.
@@ -411,4 +436,16 @@ public sealed class ApplicationIntelligenceService : IApplicationIntelligenceSer
private static string? Blank(string? value) =>
string.IsNullOrWhiteSpace(value) ? null : value.Trim();
private static string NormalizeMatchLanguage(string? declaredLanguage, string? text)
{
var language = string.IsNullOrWhiteSpace(declaredLanguage)
? LanguageDetector.Detect(text)
: declaredLanguage.Trim().ToLowerInvariant();
return language.StartsWith("nb", StringComparison.Ordinal)
|| language.StartsWith("no", StringComparison.Ordinal)
|| language.StartsWith("nn", StringComparison.Ordinal)
? "nb"
: "en";
}
}