Skip to content

feat(i18n): add Turkish locale, plus four Linux/asset fixes - #802

Closed
4ni1ak wants to merge 6 commits into
AprilNEA:masterfrom
4ni1ak:feat/turkish-locale-and-issue-fixes
Closed

feat(i18n): add Turkish locale, plus four Linux/asset fixes#802
4ni1ak wants to merge 6 commits into
AprilNEA:masterfrom
4ni1ak:feat/turkish-locale-and-issue-fixes

Conversation

@4ni1ak

@4ni1ak 4ni1ak commented Aug 23, 2026

Copy link
Copy Markdown

Summary

Adds the Turkish interface locale and fixes four reported bugs, none of which
has an open PR already. Every commit is self-contained and conventional, so this
can be rebase-merged; squashing would collapse unrelated fixes into one
subject. Happy to split it per issue if you would rather review them separately.

An earlier revision of this branch also carried fixes for #770, #752 and #688.
Those were dropped once I found #790, #765 / #719 and #741 already open for them
— no point in a second implementation of work someone else is waiting on.

Changes

openlogi-ui

  • New locales/tr.yml carrying every key en.yml defines. tr ("Türkçe") is
    registered in SUPPORTED between Svenska and Ελληνικά — native-name
    alphabetical within the Latin block — and added to the parity test's
    include_str! table, so the catalog is actually checked rather than silently
    drifting. crowdin.yml gains the language and its tr -> tr mapping.

openlogi-desktop

  • Depot metadata is now resolved through the manifest's image_metadata before
    the well-known METADATA_FILES names. Depots whose variants are handed
    rather than coloured ship none of those names — the Lift keys its metadata
    core_metadata_left.json / core_metadata_right.json — so the lookup missed,
    resolve returned None for every root, and every Lift rendered the generic
    silhouette with a complete bundle on disk. Manifest-sourced names go through
    safe_component_path like every other asset file, and the download side adds
    image_metadata to its manifest-mapped resource pass (consulting every
    model-id candidate there too, as the resolver already did).
  • The sync's depot list is deduplicated on (depot, ext) rather than the depot
    alone. Two devices sharing a depot but differing in extended_model_id — a
    colour pair, or the Lift's left- and right-handed variants — collapsed to one
    target, so the second never had its device_image /
    device_buttons_image / image_metadata fetched and stayed on fallback
    artwork with no hotspot metadata. That also undid the fix above for the
    dropped device. The collection step moved into its own function so the
    decision is testable without the surrounding HTTP. (Found by the Greptile
    review on this PR.)
  • IN_APP_UPDATES gates the updater. A Linux release publishes distro packages
    only and xtask release latest-json deliberately classifies none of them into
    the manifest, but the GUI asked anyway, so Settings → Updates answered
    "Update failed: no release asset matched the current platform (linux/x86_64)".
    The launch check, the auto-install observer and the menu action now skip it,
    and the page shows the running version plus where updates come from. macOS and
    Windows are unchanged.

openlogi-cli

  • assets sync bundles core_metadata_*.json / metadata_*.json as optional
    assets, or the resolver above would look for a file no sync ever fetched.

openlogi-inject

  • On Linux an "Open application" target is classified before it is opened: an
    executable path or a bare command name on PATH is spawned; URLs, folders,
    documents and .desktop entries stay with the opener. xdg-open opens a
    file — handed /usr/bin/nautilus it looks for a handler claiming
    application/x-executable, finds none, and does nothing, so the ring slot
    looked dead. Desktop entries deliberately stay with xdg-open, which reads
    their Exec= and honours Terminal= / StartupNotify=. The child is waited
    on from a detached thread so a long-lived app is not left a zombie. macOS and
    Windows keep going through the opener, where open / ShellExecute already
    run .app bundles and .exes.

packaging

  • The icon is installed at every standard indexed hicolor size, not only
    1024x1024. A stock hicolor/index.theme stops at 512x512, so launchers that
    resolve through the theme index found nothing. 512 down to 16 are pre-rendered
    beside the master and installed from nfpm, the Nix derivation and
    install.sh; uninstall.sh and the Nix install check cover the same set, and
    the derivation's fileset takes design/icon as a directory so a future size
    needs no second edit.

No wire types changed, so PROTOCOL_VERSION is untouched.

Testing

Run on the final rebased tree (Linux, x86_64, Rust 1.98.0):

cargo fmt --all -- --check
cargo clippy --workspace --all-targets -- -D warnings      # RUSTFLAGS=-D warnings
cargo test --workspace
RUSTDOCFLAGS="-D warnings" cargo doc --workspace --no-deps --document-private-items \
  --exclude openlogi-ui --exclude openlogi-desktop --exclude openlogi-overlay --exclude openlogi-agent
cargo xtask ci            # 6 passed, 4 skipped
cargo xtask ci wasm       # passed once wasm32-unknown-unknown was installed
cargo test -p openlogi-ui locale

All green. New regression tests:
resolves_depot_whose_metadata_is_only_named_by_the_manifest,
two_variants_of_one_depot_are_both_synced,
the_same_variant_twice_is_synced_once,
executables_are_run_and_everything_else_goes_to_the_opener,
an_executable_desktop_entry_still_goes_to_the_opener,
the_real_probes_resolve_a_shell_on_path.
The two sync tests were checked against the old key: the first fails on it, so
it pins the defect rather than the implementation.

Not run on this host — please treat as unverified:

  • shell (shellcheck / shfmt not installed). The two shell diffs were reviewed
    by hand and pass bash -n; both loops are 2-space indented with every
    expansion quoted.
  • tests (macos), cargo-deny.
  • macOS clippy — no macOS SDK here. The Windows cross-lint proxy passed, which
    covers the non-Linux side of the one #[cfg(target_os = "linux")] statement
    added to openlogi-inject.

Not runtime-tested on hardware. No Logitech device was attached, so none of
these were confirmed against a real mouse. How to check each:

Fixes #782
Fixes #797
Fixes #766
Fixes #769
Fixes #775

@4ni1ak
4ni1ak requested a review from AprilNEA as a code owner August 23, 2026 00:30
@greptile-apps

greptile-apps Bot commented Aug 23, 2026

Copy link
Copy Markdown

Greptile Summary

Adds Turkish localization and fixes reported issues across device assets, Linux application launching and packaging, updater behavior, gesture handling, battery diagnostics, and action icons.

  • Registers a complete Turkish locale and extends locale parity coverage.
  • Resolves and synchronizes manifest-selected device metadata, including distinct variants sharing one depot.
  • Disables unsupported in-app updating on Linux and clarifies package-manager updates.
  • Corrects Linux executable launching, gesture initialization, battery-voltage diagnostics, and packaged icon resources.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains; the previously reported depot-variant synchronization issue is fixed by retaining separate targets for each extended model ID.

Important Files Changed

Filename Overview
crates/openlogi-desktop/src/services/assets/sync.rs Synchronizes manifest-selected metadata and preserves separate variants by deduplicating on depot plus extended model ID.
crates/openlogi-desktop/src/services/assets.rs Resolves variant metadata through depot manifests before falling back to standard metadata filenames.
crates/openlogi-desktop/src/platform/updater.rs Gates update checks and automatic installation on platforms that publish supported in-app update artifacts.
crates/openlogi-inject/src/inject/linux.rs Distinguishes executable application targets from resources that should remain delegated to the desktop opener.
crates/openlogi-ui/src/locale.rs Registers Turkish and includes its catalog in locale parity validation.
packaging/linux/package.nix Packages the standard hicolor icon-size set and verifies installed resources.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  Registry[Asset registry] --> Targets[Device targets]
  Targets --> Key["Deduplicate by depot + variant"]
  Key --> Manifest[Resolve manifest resources]
  Manifest --> Bundle[Bundled assets]
  Manifest --> Cache[User asset cache]
  Bundle --> Resolver[Desktop asset resolver]
  Cache --> Resolver
  Resolver --> UI[Device artwork and hotspots]
Loading

Reviews (3): Last reviewed commit: "fix(gui): key the sync's depot dedup on ..." | Re-trigger Greptile

4ni1ak added 6 commits August 23, 2026 04:07
Ships `locales/tr.yml` with every key `en.yml` defines, registers `tr`
("Türkçe") in `SUPPORTED` between Svenska and Ελληνικά — native-name
alphabetical within the Latin block — and adds it to the parity test's
`include_str!` table so the catalog is actually checked rather than
silently drifting.

`crowdin.yml` gains the language and its `tr -> tr` mapping so Crowdin
round-trips the new catalog like every other one.
`load_files` accepted a depot only when it carried one of the three
hardcoded `METADATA_FILES` names. Depots whose variants are handed rather
than coloured ship none of them: the Lift keys its hotspot metadata
`core_metadata_left.json` / `core_metadata_right.json` and names the right
one in the manifest's `image_metadata` resource. The name lookup missed,
`resolve` returned `None` for every root, and every Lift and Lift for
Business rendered the generic silhouette with a complete bundle on disk.

Resolve the metadata filename through the manifest first — same model-id
candidates as the image lookup, since a manifest is keyed on whichever pid
Logi authored it against — then fall back to the well-known names for
bundles without a manifest. Manifest-sourced names now pass through
`safe_component_path` like every other asset file.

The download side has to follow, or the resolver looks for a file no sync
ever fetched: the desktop sync adds `image_metadata` to its manifest-mapped
resource pass (and consults every model-id candidate there too), and the
CLI bundle treats `core_metadata_*.json` / `metadata_*.json` as optional
assets so an offline bundle carries the variant metadata.

Fixes AprilNEA#782
The packages installed `openlogi.png` only under
`/usr/share/icons/hicolor/1024x1024/apps`. A stock `hicolor/index.theme`
stops at 512x512, so launchers that resolve icons through the theme index —
KDE's kbuildsycoca, and the GTK icon cache — found nothing and showed the
generic placeholder.

Pre-render 512 down to 16 alongside the 1024 master and install all of them
from nfpm, the Nix derivation, and `install.sh`; `uninstall.sh` and the Nix
install check cover the same set. The derivation's fileset takes
`design/icon` as a directory so a future size needs no second edit.

Fixes AprilNEA#797
Fixes AprilNEA#766
A Linux release publishes distro packages only — `.deb`, `.rpm`,
`.pkg.tar.zst` — and `xtask release latest-json` deliberately classifies
none of them into the update manifest, because those installs update
through the package manager. The GUI asked anyway, so every Linux user who
opened Settings → Updates and clicked Check got a red "Update failed:
no release asset matched the current platform (linux/x86_64)".

Gate the updater on a single `IN_APP_UPDATES` const: the launch check, the
auto-install observer, and the menu action skip the check where a release
carries no in-place-updatable artifact, and the Updates page shows the
running version plus where updates come from instead of a check button and
two switches that cannot do anything. macOS and Windows are unchanged.

The new string is added to all 22 catalogs at the same position.

Fixes AprilNEA#769
`Action::OpenApplication` handed its target straight to `opener::open`,
which on Linux is `xdg-open` — and xdg-open *opens* a file. Given
`/usr/bin/nautilus` it looks for a handler claiming
`application/x-executable`, finds none, and does nothing at all, so the
Actions Ring slot appeared dead.

On Linux, classify the target first: an executable file path or a bare
command name resolved on `PATH` is spawned as a program; URLs, folders,
documents, and `.desktop` entries stay with the opener — a desktop entry
especially, since xdg-open reads its `Exec=` and honours `Terminal=` and
`StartupNotify=`, none of which spawning the file would. macOS and Windows
keep going through the opener, where `open`/`ShellExecute` already run
`.app` bundles and `.exe`s.

The child is waited on from a detached thread so a long-lived app does not
sit as a zombie for the agent's lifetime. The decision table takes its two
filesystem probes as parameters, so it is tested with fakes; one further
test pins the real probes against `sh` on `PATH`.

Fixes AprilNEA#775
`sync` collected one target per connected device, each carrying the HID++
`extended_model_id` its manifest-mapped resources are keyed on, then
deduplicated the list on the depot alone. Two devices sharing a depot but
differing in that byte — a colour pair, or the Lift's left- and
right-handed variants — collapsed to one target, so `sync_depot` never saw
the second and its `device_image` / `device_buttons_image` /
`image_metadata` were never fetched. That device stayed on fallback artwork
with no hotspot metadata.

Deduplicate on `(depot, ext)` instead. The baseline files the extra pass
re-requests are cache hits, so the cost is one manifest read per variant.

The collection step moves into its own function so the decision is testable
without the surrounding HTTP: `two_variants_of_one_depot_are_both_synced`
fails on the old key, and `the_same_variant_twice_is_synced_once` pins that
repeated snapshots of one device still collapse.
@4ni1ak
4ni1ak force-pushed the feat/turkish-locale-and-issue-fixes branch from 11bff08 to 78609e8 Compare August 23, 2026 01:10
@4ni1ak 4ni1ak changed the title feat(i18n): add Turkish locale, plus seven reported bug fixes feat(i18n): add Turkish locale, plus four Linux/asset fixes Aug 23, 2026
@AprilNEA

Copy link
Copy Markdown
Owner

Thanks for putting this together. The individual changes look useful, but could you please split this into focused PRs before we continue the review?

Suggested split:

  1. Turkish locale
  2. Lift manifest metadata resolution and variant sync (#782)
  3. Linux hicolor icon packaging (#766 / #797)
  4. Linux package-manager update UI (#769)
  5. Linux “Open application” executable launching (#775)

The manifest metadata lookup and the (depot, extended_model_id) sync deduplication should stay together, since they are two parts of the same asset fix.

Keeping the commits separate helps, but it does not remove the PR-level coupling: these changes span localization, device assets, packaging, the updater, and input injection, with different review and verification requirements. Several touched files also overlap active PRs such as #751, #756, #764, and #785, so one conflict or requested change currently blocks every unrelated fix.

Separate PRs would let us review, test, and merge each change independently. Please keep each Fixes #… line in its corresponding PR. Thanks!

@4ni1ak

4ni1ak commented Aug 23, 2026

Copy link
Copy Markdown
Author

Agreed — split as suggested. Closing this in favour of five independent PRs:

Each branches off current master, carries its own Fixes line, and passes
fmt / clippy / the workspace tests on its own tree.

Kept together as you asked: the manifest metadata lookup and the sync dedup are
both in #836 — the second is what makes the first hold once two variants of one
depot are connected, so splitting them would leave a half-fix.

One ordering note, since it is the only remaining coupling: #838 adds a string to
every catalog that exists today, and #835 adds tr.yml. Whichever lands second
needs a rebase before the locale parity test passes. Ping me and I will rebase —
no preference on the order.

On the Greptile finding from this PR: the depot dedup keyed on the depot alone
while each target carried the extended_model_id its manifest-mapped resources
are keyed on, so a colour pair (or the Lift's left/right variants) collapsed to
one target and the second variant's device_image / device_buttons_image /
image_metadata were never fetched — which also undid the metadata fix for that
device. It is fixed in #836, deduplicating on (depot, ext), with the collection
step extracted so it is testable without the surrounding HTTP.

Also dropped along the way: this branch originally carried fixes for #770, #752
and #688 as well. #790, #765 / #719 and #741 are already open for those, so there
was no reason for a second implementation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment