Skip to content

M17: language reach - #29

Merged
SebHenn merged 4 commits into
mainfrom
m17-language-reach
Nov 7, 2026
Merged

SebHenn merged 4 commits into
mainfrom
m17-language-reach

Conversation

@SebHenn

@SebHenn SebHenn commented Nov 7, 2026 •

Copy link
Copy Markdown
Owner

What

M17 "Language reach" from the roadmap. A translator without Git can work in Weblate once it is set up, missing translations fail a test, counts follow each language's plural rules, item text carries its language, and dates follow the archive's languages without losing anything accepted before.

Translations

  • A test reads every text from the code (T[...], localizer[...], .Plural(...), attribute names and messages) and fails when a language the interface offers lacks one, or when a translation is left over, empty, loses a {0} or lacks a form of a count. It found five German texts nothing used any more, which are gone.
  • It also writes Resources/SharedResource.resx, the English base file Weblate needs, since English is the key in the code. The file is not built into the app, so an untranslated text is still recognised as English. Translations of consent and privacy texts carry a note asking for a second translator.
  • Languages still in progress in Weblate may have gaps, which show in English. A language must be complete once it is added to SupportedLanguages.cs.

Counts

  • The spike's choice is ICU MessageFormat inside RESX values: {0, plural, one {# day} other {# days}}. Weblate checks it with the icu-message-format flag, and nothing else changes for ASP.NET. Plurals.cs reads that part of ICU and has the CLDR rules for whole numbers in about 60 languages. A text nobody translated keeps English rules, so a Polish reader of English text never gets a missing form. docs/translating.md compares it with PO and JSON formats.
  • The 18 texts that had a count inside a sentence ("for 30 days", "at most 20 photos") now use it. The others keep label form (Photos: {0}).

Content language

  • "Settings" has the language of the material, from every language .NET knows, or "Several languages, none of them most". Below it, the languages dates can also be written in.
  • Item pages, cards, collection pages and feed entries mark what curators and contributors wrote with lang, never the interface's words around it. "Several" marks nothing. Without a choice it is the archive's language.
  • Dates are read in the material's languages and in the language of whoever types them. Month names come from .NET for every language, with genitive forms ("12 marca 1953") and without accents ("Marz 1953"). The words for "circa", "before" and so on are a DateVocabulary per language, English and German so far. A month name with two meanings ("listopad") is read in the archive's language first.
  • The export README is in the exporting admin's language, with README.en.txt beside it. The export has the two new settings.

Please decide or look at

  • Nothing changes for existing archives until an admin saves the settings, and saving them without a change keeps it so. Until then, dates are read in English and German, as before, and the material counts as being in the archive's language. A German archive full of English material would claim German for it. "Several languages" is the way out, and the changelog says so.
  • Once an admin chooses, German words stop working in an English-only archive, unless German is ticked or the curator reads German. That is the policy the roadmap set (the material's languages plus the reader's). The settings page offers the old pair when nothing was chosen.
  • Dates are a little more forgiving. "Marz 1953" and "ungefahr 1950" are now read as March and as circa, where before the word was ignored and the year read on its own. Stored dates are not read again, so no item changes.
  • Weblate is decided, but not set up: Hosted Weblate, on its gratis plan for libre projects. That needs you to apply. docs/translating.md has the settings, including Signed-off-by: {{ author }} in the commit message, so its pull requests pass the sign-off check, and the license agreement translators accept. Weblate's docs do not say exactly how {{ author }} is written, so check the first pull request.
  • No language per item. Mixed archives choose "several". Recorded in the roadmap as wanted only if they ask.
  • A migration adds ContentLanguage and OtherContentLanguages to the settings, empty for existing archives.

Checked

  • 342 HTTP and unit tests and 163 browser tests pass locally, built the way CI builds, and on CI.
  • A frozen copy of the old date reader is in the tests. FsCheck builds 3,000 dates from the words and numbers people used before, and every one the old reader accepted must mean the same days now, without a setting and after saving it unchanged, for English and German readers. The examples people were given in help texts are checked one by one as well.
  • Polish counts are checked for 0, 1, 2, 4, 5, 12, 13, 21, 22, 25, 102, 112 and 1,000, and other languages' rules for their edge cases. A language without translations (Polish, as a test language) shows "for 30 days" in English.
  • 33 rules broken on purpose, one at a time, and all caught, each by the test meant for it. Dates: their words, the old default, the reader's language, accents, genitive month names, clashes, and requests that ignore the setting. Counts: plural rules, untranslated text, exact numbers, a missing other. German translations that are missing, empty, left over, or lose a placeholder or a form, plus a new text without the base file, and the base file built into the app. lang: "several", the description, cards and the feed. Settings and the export.
  • Two of them were missed at first, and the tests are better for it. The test for untranslated text used Polish, whose rules give English's result, so it now uses Russian (21) and French (0). A settings page opened before the update and sent afterwards would have reset the chosen languages, and now a test sends one.
  • Walked through in the running app, with the German demo: an English reader gets the demo's text marked de and the words around it not. On the settings page there are 252 languages, at desktop and phone width and in German. After choosing Polish, "12 marca 1953" is a day, "listopad" is November, and the edit page reads "12 października 1953". A German reader is understood in German again. "Several" marks nothing, also in the feed.
  • The walk-through found two things, both fixed. The main language was offered again under "Dates can also be written in". In German, "Daten" could be read as "data", so these texts say "Datumsangaben".

Not checked

  • Weblate itself. No translator has tried it, because it is not set up. It is task D in docs/usability-test.md.
  • Screen readers switching voice for the marked text. It is the standard attribute, but nobody listened.
  • Month names in languages beyond the ones in the tests come from .NET's data as they are.

🤖 Generated with Claude Code

SebHenn and others added 4 commits November 7, 2026 16:00
…nt in every language

- A test reads every text from the code and fails when a translation is missing, left over or loses a
  placeholder. It keeps Resources/SharedResource.resx, the English base file Weblate needs, up to date.
- Counts in sentences use ICU MessageFormat plurals, with CLDR rules for each language, so that Polish
  can say 1 zdjęcie, 2 zdjęcia, 5 zdjęć. A translation must give every form its language needs.
- Admins choose the language of the material. Dates are read in it, in the other languages chosen, and
  in the language of whoever types them. Month names come from .NET for any language, without accents.
  Archives that have not chosen read English and German as before; a frozen copy of the old reader in
  the tests checks that every date it accepted still means the same.
- Item text carries the material's lang, on the page, in lists and in the feed.
- The export README is translated, with an English copy when it is not in English.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Seb H. <138793908+SebHenn@users.noreply.github.com>
…ttings

Only languages the interface offers must be complete, so Weblate can bring a new one in parts.
An empty translation fails a test, because it would show nothing at all.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Seb H. <138793908+SebHenn@users.noreply.github.com>
The test for untranslated text now uses Russian and French, whose rules differ from English for 21 and 0.
With Polish it could not fail.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Seb H. <138793908+SebHenn@users.noreply.github.com>
… old form is sent

The walk-through showed the main language offered again under "Dates can also be written in".
In German, "Daten" can be read as "data", so these texts say "Datumsangaben".
A test now checks that the English base file is not built into the application.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Seb H. <138793908+SebHenn@users.noreply.github.com>
@SebHenn
SebHenn marked this pull request as ready for review November 7, 2026 16:22
@SebHenn
SebHenn merged commit 6796440 into main Nov 7, 2026
12 checks passed
@SebHenn
SebHenn deleted the m17-language-reach branch November 7, 2026 17:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant