Skip to content

Region-specific symbols pages matching physical keyboard layouts - #2681

Draft
MiMoHo wants to merge 11 commits into
HeliBorg:mainfrom
MiMoHo:symbols-regional-layouts
Draft

Region-specific symbols pages matching physical keyboard layouts#2681
MiMoHo wants to merge 11 commits into
HeliBorg:mainfrom
MiMoHo:symbols-regional-layouts

Conversation

@MiMoHo

@MiMoHo MiMoHo commented Jul 20, 2026

Copy link
Copy Markdown

What

Region-specific symbols pages: the first row of the symbols layout (which also feeds the digit long-press popups and the symbol hints on the letter keys) matches the Shift+digit row of the user's physical keyboard layout instead of being US-only for everyone.

  • 9 new layout files under layouts/symbols/ (symbols_de, _nordic, _uk, _es, _it, _iso, _br, _tr, _ch; the existing symbols_arabic is untouched), each identical to the default symbols.txt except for the regionalized rows. Every Shift row was verified against kbdlayout.info (sources in the table below).
  • Wired via the existing KeyboardLayoutSet=…|SYMBOLS:… extra value in method.xml (the mechanism symbols_arabic already uses) for 26 subtypes: de, de-DE, de-CH, fr-CH, it-CH, sv, da, nb, fi, et-EE, en-GB, es, ca, gl-ES, eu-ES, it, is, pt-PT, es-419, es-US, hr, sr-Latn, sr, sl, pt-BR, tr. The US/default page and all other subtypes are untouched. No framework changes.
  • Pref migration + self-healing so the changed extra values don't break existing users: an AppUpgrade step extends stored subtype prefs (enabled/selected/additional/per-app) with the regional SYMBOLS entry unless one was chosen explicitly, and SubtypeSettings now heals stale serializations at load time (this also fixes a pre-existing silent-reset when method.xml extra values change, plus a tautological comparison in getSelectedSubtype).
  • Tests: first-row invariant for every symbols layout (10 keys, % reachable — the number-row coupling and % symbol is hard to find - no redundancy #428), all KeyboardLayoutSet references in method.xml must exist as assets, symbols-override removal keeps the subtype enabled, and an end-to-end stale-pref healing test.
  • Translations for the new layout-name strings in 17 languages (new strings only, per the CONTRIBUTING exception).
  • CI: the test workflow's path filter now also triggers on assets/, res/xml/, and test changes (previously a PR touching only layouts or method.xml ran no CI).
file Shift row 1→0 subtypes source
symbols_de ! " § $ % & / ( ) = de, de-DE kbdlayout.info/kbdgr
symbols_nordic ! " # ¤ % & / ( ) = sv, da, nb, fi, et-EE kbdsw/kbdfi/kbdda/kbdno/kbdest
symbols_uk ! " £ $ % ^ & * ( ) en-GB kbduk
symbols_es ! " · $ % & / ( ) = es, ca, gl-ES, eu-ES kbdsp
symbols_it ! " £ $ % & / ( ) = it kbdit
symbols_iso ! " # $ % & / ( ) = is, pt-PT, es-419, es-US, hr, sr-Latn, sr, sl kbdic/kbdpo/kbdla/kbdcr/kbdycc
symbols_br ! @ # $ % ¨ & * ( ) pt-BR kbdbr
symbols_tr ! ' ^ + % & / ( ) = tr kbdtuq
symbols_ch + " * ç % & / ( ) = de-CH, fr-CH, it-CH kbdsg

Why

Notes / open questions for you

This is a draft mainly because of one policy question: wiring SYMBOLS: in method.xml changes the default for existing users of those subtypes (they'd see the regional first row after updating — the migration keeps everything else seamless). Three ways to ship it, all supported by this implementation:

  1. As-is (default wiring + migration) — precedent: the symbols_arabic wiring; strongest fix for Symbols for language #1384.
  2. Gated behind a setting ("adapt symbols to keyboard region", default off) — precedent: Layout for shift + long press on number row #1400, Show popup hints on number row #1303.
  3. Picker-only: drop the method.xml/migration commits and ship the layouts purely as selectable options in the existing symbols-layout picker (zero default change; discoverability is low, but it's a strict superset of today).

Happy to rework to (2) or (3) — the layout files, tests, healing, and translations are identical in all three variants.

Deliberately not included (documented reasoning available): regional More-Symbols/number-row files (would duplicate centralized currency/number-row logic), inverted layouts (AZERTY/CZ/SK/HU/LT — different mapping, later wave), Macedonian (typographic quotes in its Shift row, special case).

Refs #1384, #428. Supersedes #2630, #2621.

MiMoHo and others added 11 commits July 19, 2026 22:37
Instead of changing the shared default symbols layout for everyone (which
disrupts existing muscle memory, cf. the discussion on HeliBorg#2630 and HeliBorg#2621),
the symbols page now follows the secondary (Shift) layer of each region's
physical keyboard, wired per subtype via the existing SYMBOLS: extra value
mechanism (previously only used for symbols_arabic).

Each new symbols_<region>.txt equals the default symbols.txt but with its
first row replaced by that region's shifted number row, so long-pressing a
digit yields what Shift+digit yields on the matching hardware keyboard
(number rows cross-checked against kbdlayout.info KLC sources):

  symbols_de      ! " § $ % & / ( ) =   -> de, de-DE
  symbols_nordic  ! " # ¤ % & / ( ) =   -> sv, da, nb, fi, et-EE
  symbols_uk      ! " £ $ % ^ & * ( )   -> en-GB
  symbols_es      ! " · $ % & / ( ) =   -> es, ca, gl-ES, eu-ES

The US/QWERTY default is untouched. This makes § discoverable on German
QWERTZ (Shift+3) without a global change (refs HeliBorg#2621), and reframes symbol
placement as regional rather than a one-size-fits-all default (refs HeliBorg#2630).
Icelandic is intentionally left out of the Nordic group (its Shift+4 is $,
not ¤).

SubtypeTest.subtypeStaysEnabledOnEdits assumed the es resource subtype has
no SYMBOLS layout; the revert step now returns to the actual resource
subtype so the test is robust to regional overrides.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…nvariant test

Adds four more regional symbols pages, following the same pattern (first row =
the region's shifted number row, cross-checked against kbdlayout.info KLC
sources); the US/QWERTY default stays untouched:

  symbols_it   ! " £ $ % & / ( ) =   -> it
  symbols_iso  ! " # $ % & / ( ) =   -> is, pt-PT, es-419, es-US, hr, sr-Latn, sl
  symbols_br   ! @ # $ % ¨ & * ( )   -> pt-BR (ABNT2)
  symbols_tr   ! ' ^ + % & / ( ) =   -> tr (Turkish-Q)

symbols_iso is the generic ISO shifted number row (# on 3) shared by the regions
that use it identically, so seven subtypes reuse one file instead of seven near-
duplicates (the layout picker lists every file unfiltered, so fewer files = less
clutter).

Scope stays SYMBOLS-only: no MORE_SYMBOLS/NUMBER_ROW region files, since currency
($$$) and localized digits ([number_row]) are already handled by centralized,
locale-driven logic that these must not duplicate.

New ParserTest.symbolsLayoutsFirstRowInvariant enforces the load-bearing coupling
for every symbols/*.txt: the first row must have exactly 10 keys (it is mapped 1:1
onto the number row for digit long-press hints and alphabet-key symbol hints) and
must keep % reachable there even without the number row (guards issue HeliBorg#428).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The regional symbols files were accidentally created from a working copy that
still had the PR HeliBorg#2630 &/- swap in the second row, so every region file differed
from the default in two ways instead of one. Restore the default order (& before
-) so the only intended difference from symbols.txt is the first row (the
region's shifted number row).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Extend the regional principle from the shifted number row (row 1) to the direct
symbol keys: in every region file place _ adjacent to - (they are the same
physical key everywhere, _ = Shift+-), and drop & from the direct row since on
these keyboards & sits on the number-row shift layer (DE Shift+6, UK/BR Shift+7)
and is therefore already the digit long-press hint. & stays reachable via that
hint and the punctuation long-press cluster. The US/QWERTY default is untouched,
so this resolves the -/_ adjacency (refs HeliBorg#2630) regionally rather than globally.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…popup

On UK and ABNT2 hardware, = \ and | are base-level keys, so hardware
faithfulness cuts the other way for them: add = to the + popups and
\ | to the / popups in symbols_uk/symbols_br (row 2, which is never
replaced by the number row). Give the ABNT2 ¨ key its dead-accent
family as popups. Remove the duplicate · from the - popup in
symbols_es (it is a direct row-1 key there).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Enabled and selected subtypes are stored as full serializations, so
changing a resource subtype's extra value (e.g. adding a SYMBOLS
layout) made exact-match consumers fail: getSelectedSubtype fell back
to the first enabled subtype (wrong language after upgrade), and
changeAdditionalSubtype computed isEnabled/isSelected as false, so
edits silently did not take effect. loadEnabledSubtypes already
resolves such entries by locale + main layout; now it also writes the
resolved serialization back, and getSelectedSubtype falls back to a
locale + main layout match (preferring resource subtypes) and heals
its pref. Also fix a tautological comparison in the default-subtypes
fallback and the missing qwerty normalization in the
disable-changed-builtin workaround.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Extend stored subtype prefs (enabled, selected, additional, per-app)
of the 22 rewired locales with the regional SYMBOLS layout, unless one
was chosen explicitly. This keeps stored prefs matching the changed
resource subtypes and brings the regional symbols page to existing
additional subtypes, including the shipped default German (QWERTY)
subtype, which now also carries symbols_de for new installs. Runs via
checkVersionUpgrade, so backup restores are covered too; subtypes are
reloaded afterwards because SubtypeSettings.init already ran on the
not-yet-migrated prefs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- symbolsLayoutsFirstRowInvariant: guard against silently passing when
  the layouts directory is not found
- allResourceSubtypeLayoutsExist: every layout referenced by a
  KeyboardLayoutSet extra value in method.xml must exist as an asset
  (a typo silently falls back to the default layout otherwise)
- symbolsOverrideCanBeRemoved: removing a resource subtype's SYMBOLS
  override keeps the subtype enabled as an additional subtype
- stalePrefsHealAfterResourceSubtypeChange: pre-change pref
  serializations heal on load, selection survives by locale + main
  layout match, and edits take effect afterwards

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The test workflow only triggered on app/src/main/java changes, so PRs
touching layouts, method.xml, or the tests themselves ran no CI at all.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
symbols_ch carries the Swiss Shift+digit row (+ " * ç % & / ( ) =,
kbdlayout.info/kbdsg) shared by the German, French, and Italian Swiss
layouts; ç is a hardware-faithful direct key and useful for French.
Serbian Cyrillic gets symbols_iso: its physical Shift row (KBDYCC) is
identical to the Latin one, and Serbian users commonly switch scripts
on one keyboard. The upgrade migration covers the four subtypes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
New resource strings only, following each file's existing style for
layout_symbols_arabic; per CONTRIBUTING, new strings may be added
directly (existing translations are untouched and stay on Weblate).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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