- Introduced language normalization utility functions to standardize language codes across the application. - Updated ContractUploadController to resolve requested language from contract data and user settings. - Enhanced authMiddleware to set preferred language in user object based on user settings. - Added preferred_language column to user_settings table in the database. - Implemented UserSettingsRepository to manage user settings, including preferred language updates. - Updated DocumentTemplateService and AboContractService to support language-specific templates. - Enhanced InvoiceService to select invoice templates based on normalized language codes. - Added new script to compare versions of ABO contract documents. - Refactored various services and repositories to utilize the new language normalization logic.
89 lines
2.7 KiB
JavaScript
89 lines
2.7 KiB
JavaScript
const BUILTIN_LANGUAGES = [
|
|
{ languageCode: 'de', label: 'Deutsch', isEnabled: true, isCustom: false },
|
|
{ languageCode: 'en', label: 'English', isEnabled: true, isCustom: false },
|
|
{ languageCode: 'sl', label: 'Slovenian', isEnabled: true, isCustom: false },
|
|
];
|
|
|
|
function normalizeLanguageCode(value) {
|
|
const raw = String(value == null ? '' : value).trim();
|
|
if (!raw) return '';
|
|
|
|
const normalized = raw.replace('_', '-');
|
|
if (!/^[a-z]{2,5}(?:-[a-zA-Z0-9]{2,8})?$/.test(normalized)) {
|
|
return '';
|
|
}
|
|
|
|
return normalized.toLowerCase();
|
|
}
|
|
|
|
function normalizeBoolean(value, fallback) {
|
|
if (value === undefined || value === null) return fallback;
|
|
if (typeof value === 'boolean') return value;
|
|
|
|
const normalized = String(value).trim().toLowerCase();
|
|
if (['1', 'true', 'yes', 'on'].includes(normalized)) return true;
|
|
if (['0', 'false', 'no', 'off'].includes(normalized)) return false;
|
|
return fallback;
|
|
}
|
|
|
|
function compareLanguageCodes(left, right) {
|
|
const order = ['de', 'en', 'sl'];
|
|
const leftIndex = order.indexOf(left);
|
|
const rightIndex = order.indexOf(right);
|
|
|
|
if (leftIndex !== -1 || rightIndex !== -1) {
|
|
if (leftIndex === -1) return 1;
|
|
if (rightIndex === -1) return -1;
|
|
return leftIndex - rightIndex;
|
|
}
|
|
|
|
return left.localeCompare(right);
|
|
}
|
|
|
|
function mergeLanguageDescriptors(rows = []) {
|
|
const merged = new Map();
|
|
|
|
BUILTIN_LANGUAGES.forEach((entry) => {
|
|
merged.set(entry.languageCode, { ...entry });
|
|
});
|
|
|
|
rows.forEach((row) => {
|
|
const languageCode = normalizeLanguageCode(
|
|
row?.languageCode ?? row?.language_code ?? row?.code ?? row?.lang,
|
|
);
|
|
if (!languageCode) return;
|
|
|
|
const existing = merged.get(languageCode) || {
|
|
languageCode,
|
|
label: languageCode.toUpperCase(),
|
|
isEnabled: true,
|
|
isCustom: true,
|
|
};
|
|
|
|
const label = String(row?.label ?? row?.name ?? existing.label ?? languageCode.toUpperCase()).trim() || existing.label;
|
|
|
|
merged.set(languageCode, {
|
|
...existing,
|
|
languageCode,
|
|
label,
|
|
isEnabled: normalizeBoolean(row?.isEnabled ?? row?.is_enabled, existing.isEnabled),
|
|
isCustom: normalizeBoolean(row?.isCustom ?? row?.is_custom, existing.isCustom),
|
|
});
|
|
});
|
|
|
|
return Array.from(merged.values()).sort((left, right) => compareLanguageCodes(left.languageCode, right.languageCode));
|
|
}
|
|
|
|
function resolveDocumentTemplateStorageFolder(languageCode) {
|
|
const normalized = normalizeLanguageCode(languageCode);
|
|
if (normalized === 'en') return 'english';
|
|
if (normalized === 'de') return 'german';
|
|
return normalized || 'other';
|
|
}
|
|
|
|
module.exports = {
|
|
BUILTIN_LANGUAGES,
|
|
mergeLanguageDescriptors,
|
|
normalizeLanguageCode,
|
|
resolveDocumentTemplateStorageFolder,
|
|
}; |