diff --git a/internal/i18n/untranslated_test.go b/internal/i18n/untranslated_test.go new file mode 100644 index 0000000..c68d2a4 --- /dev/null +++ b/internal/i18n/untranslated_test.go @@ -0,0 +1,70 @@ +package i18n + +import ( + "os" + "path/filepath" + "regexp" + "strings" + "testing" +) + +// Danish prose left in a component is the failure the dictionaries cannot see. +// +// `i18n_test.go` checks that the two dictionaries agree. It cannot check the thing +// that actually went wrong: a string that was never put in either, because nobody +// noticed it. Three survived the sweep — "Ingen nyere version fundet.", "Ikke mere +// i dag." and a token hint split across two lines — and they survived it for the +// same reason. The sweep grepped for æøå, and none of them contain one. +// +// So this reads the templates instead and looks for the words that give Danish +// away whatever letters it happens to use. A word list rather than a language +// detector: this repository ships one static binary, and a list of thirty common +// words catches the sentences a person would actually write. +func TestNoDanishProseOutsideTheDictionaries(t *testing.T) { + // Text nodes of three characters or more, and the three attributes a person + // reads. Anything inside {…} is already an expression — usually a t() call — + // and is not what this is looking for. + text := regexp.MustCompile(`>\s*([^<>{}\n][^<>{}]{3,})\s*<`) + attrs := regexp.MustCompile(`(?:aria-label|title|placeholder)="([^"{][^"]{3,})"`) + // Words that are Danish and are not also English. "is", "for" and "to" would + // match English prose and are deliberately absent. + danish := regexp.MustCompile(`(?i)\b(og|er|ikke|det|den|der|til|kan|som|har|med|af|en|et|du|din|dine|vises|ingen|nyere|fundet|ude|valgt|slettet|gemt|opgave|projekt|indstillinger|fjern|opret|vælg|luk|tilføj|ryd|gem|slet|omdøb)\b`) + comments := regexp.MustCompile(`(?s)`) + styles := regexp.MustCompile(`(?s)