LOLYO-Export: typografische Zeichen auf ASCII
Der Gedankenstrich kam im Zielsystem als "–" an -- seine UTF-8-Bytes, gelesen als Windows-1252. Nachgemessen hat die Vorlage des Anbieters dieselbe Kodierung wie unsere Datei: UTF-8 ohne BOM, zu sehen an dem "bestätigt" in ihrer Kopfzeile. Die Ursache liegt also nicht in dem, was wir schreiben, und solange sie nicht geklaert ist, geht der Weg ueber das Zeichen selbst: ein Bindestrich sagt dasselbe und ist in beiden Kodierungen dasselbe Byte. Gilt fuer jede Zelle aus den Daten, nicht nur fuer die Position -- aufgefallen ist es dort, weil die Taetigkeiten einen Gedankenstrich fuehren, aber dieselben Zeichen stehen auch in Namen und Titeln. Zwei Ausnahmen: Umlaute bleiben, weil "Baeckerei" ein Problem verstecken wuerde, das dann auch Namen betraefe. Und das Passwort bleibt Zeichen fuer Zeichen, wie es ist -- ein ersetztes Zeichen faellt niemandem auf, es gibt dann nur ein Konto, in das niemand hineinkommt.
This commit is contained in:
47
lib/lolyo.ts
47
lib/lolyo.ts
@@ -59,6 +59,30 @@ export function anrede(gender: string): string {
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Typografische Zeichen auf ihre ASCII-Entsprechung.
|
||||
*
|
||||
* Im Zielsystem kam der Gedankenstrich „–" als `–` an — das sind seine
|
||||
* UTF-8-Bytes, gelesen als Windows-1252. Gemessen hat die Vorlage des Anbieters
|
||||
* dieselbe Kodierung wie unsere Datei (UTF-8 ohne BOM, nachgeprüft am
|
||||
* „bestätigt" in ihrer Kopfzeile), die Ursache liegt also nicht in dem, was wir
|
||||
* schreiben. Solange sie nicht geklärt ist, geht der Weg über das Zeichen
|
||||
* selbst: ein Bindestrich sagt dasselbe und überlebt jede Fehlinterpretation,
|
||||
* weil er in beiden Kodierungen dasselbe Byte ist.
|
||||
*
|
||||
* Umlaute bleiben. „Bäckerei" zu „Baeckerei" zu machen hiesse, ein Problem zu
|
||||
* verstecken, das es entweder gar nicht gibt — oder das dann auch Namen
|
||||
* betrifft, und dort wäre es keine Kosmetik mehr.
|
||||
*/
|
||||
export function ohneTypografie(text: string): string {
|
||||
return text
|
||||
.replace(/[‐-―−]/g, "-")
|
||||
.replace(/[‘’‚‛′]/g, "'")
|
||||
.replace(/[“”„‟″]/g, '"')
|
||||
.replace(/…/g, "...")
|
||||
.replace(/[ ]/g, " ");
|
||||
}
|
||||
|
||||
/** Die Person, so wie der Export sie braucht. */
|
||||
export type LolyoQuelle = {
|
||||
id: string;
|
||||
@@ -86,17 +110,26 @@ export type LolyoZeile = Record<string, string>;
|
||||
* employees.email: die Datei legt Konten bei einem fremden Anbieter an.
|
||||
*/
|
||||
export function baueLolyoZeile(p: LolyoQuelle, passwort: string): LolyoZeile {
|
||||
// ohneTypografie steht an jeder Zelle, die aus den Daten kommt, und nicht nur
|
||||
// an der Position: aufgefallen ist es dort, weil die Tätigkeiten einen
|
||||
// Gedankenstrich führen — dieselben Zeichen stehen aber auch in Namen und
|
||||
// Titeln, und die fielen erst bei der Person auf, die einen trägt.
|
||||
const aus = (wert: string) => ohneTypografie(wert);
|
||||
|
||||
return {
|
||||
"Benutzer/Code": p.id,
|
||||
Email: p.company_email ?? "",
|
||||
Email: aus(p.company_email ?? ""),
|
||||
// **Ohne** Umschrift: das Passwort muss Zeichen für Zeichen das sein, was
|
||||
// die Person eingibt. Ein ersetztes Zeichen fiele niemandem auf — es gäbe
|
||||
// nur ein Konto, in das niemand hineinkommt.
|
||||
Passwort: passwort,
|
||||
"Titel prefix": p.title_prefix.join(" "),
|
||||
Vorname: p.first_name,
|
||||
Nachname: p.last_name,
|
||||
"Title Suffix": p.title_suffix.join(" "),
|
||||
Position: p.job_title,
|
||||
"Titel prefix": aus(p.title_prefix.join(" ")),
|
||||
Vorname: aus(p.first_name),
|
||||
Nachname: aus(p.last_name),
|
||||
"Title Suffix": aus(p.title_suffix.join(" ")),
|
||||
Position: aus(p.job_title),
|
||||
Gruppen: LOLYO_GRUPPE,
|
||||
Telefon: p.phone ?? "",
|
||||
Telefon: aus(p.phone ?? ""),
|
||||
Anrede: anrede(p.gender),
|
||||
Sprache: LOLYO_SPRACHE,
|
||||
"E-Mail bestätigt": LOLYO_EMAIL_BESTAETIGT,
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
LOLYO_SPALTEN,
|
||||
LOLYO_SPRACHE,
|
||||
lolyoSpalten,
|
||||
ohneTypografie,
|
||||
type LolyoQuelle,
|
||||
} from "@/lib/lolyo";
|
||||
|
||||
@@ -107,6 +108,42 @@ describe("Die Zuordnung", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("Typografische Zeichen", () => {
|
||||
it("weichen dem Bindestrich", () => {
|
||||
// Der Gedankenstrich kam im Zielsystem als „–" an. Ein Bindestrich sagt
|
||||
// dasselbe und ist in beiden Kodierungen dasselbe Byte.
|
||||
expect(ohneTypografie("Angestellte/r – F&E")).toBe("Angestellte/r - F&E");
|
||||
expect(ohneTypografie("Lehrling — Wolkersdorf")).toBe("Lehrling - Wolkersdorf");
|
||||
});
|
||||
|
||||
it("gelten für Anführungszeichen, Auslassungspunkte und geschützte Leerzeichen", () => {
|
||||
expect(ohneTypografie("„Schnitte“")).toBe('"Schnitte"');
|
||||
expect(ohneTypografie("O’Brien")).toBe("O'Brien");
|
||||
expect(ohneTypografie("und so weiter …")).toBe("und so weiter ...");
|
||||
expect(ohneTypografie("W 17")).toBe("W 17");
|
||||
});
|
||||
|
||||
it("lassen Umlaute in Ruhe", () => {
|
||||
// „Bäckerei" zu „Baeckerei" zu machen hiesse, ein Problem zu verstecken,
|
||||
// das dann auch Namen beträfe — und dort wäre es keine Kosmetik mehr.
|
||||
expect(ohneTypografie("Arbeiter/in – Bäckerei")).toBe("Arbeiter/in - Bäckerei");
|
||||
expect(ohneTypografie("Müller-Weiß")).toBe("Müller-Weiß");
|
||||
});
|
||||
|
||||
it("gelten für jede Zelle aus den Daten, nicht nur für die Position", () => {
|
||||
const z = zeile({ job_title: "Angestellte/r – F&E", last_name: "O’Brien", title_suffix: ["M–A"] });
|
||||
expect(z.Position).toBe("Angestellte/r - F&E");
|
||||
expect(z.Nachname).toBe("O'Brien");
|
||||
expect(z["Title Suffix"]).toBe("M-A");
|
||||
});
|
||||
|
||||
it("gelten nicht für das Passwort", () => {
|
||||
// Ein ersetztes Zeichen fiele niemandem auf — es gäbe nur ein Konto, in
|
||||
// das niemand hineinkommt.
|
||||
expect(baueLolyoZeile(person(), "Pass–wort–2026").Passwort).toBe("Pass–wort–2026");
|
||||
});
|
||||
});
|
||||
|
||||
describe("Die Datei", () => {
|
||||
it("ist semikolongetrennt und ohne BOM", () => {
|
||||
// Das BOM hinge unsichtbar am Namen der ersten Spalte, und
|
||||
|
||||
Reference in New Issue
Block a user