Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ jobs:
with:
persist-credentials: false
- name: Publication inputs
run: python3 scripts/check_publication.py
run: |
python3 scripts/check_publication.py
python3 scripts/check_localizations.py
- name: Publication check regressions
run: python3 -m unittest discover -s Tests/PublicationChecks
- name: Swift tests
Expand All @@ -45,6 +47,8 @@ jobs:
with:
persist-credentials: false
- name: Publication inputs
run: python3 scripts/check_publication.py
run: |
python3 scripts/check_publication.py
python3 scripts/check_localizations.py
- name: Publication check regressions
run: python3 -m unittest discover -s Tests/PublicationChecks
3 changes: 3 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ These principles apply in every session, including work based on research, commu
- Every added feature requires human review and manual validation by the maintainer (the user). Automated tests, successful compilation and agent reviews support that decision; they do not replace it.
- Complete the implementation and appropriate automated checks, then provide a concrete build and focused manual checks covering the intended behavior, relevant failure triggers and regressions. Until the user confirms the outcome, report the feature as **awaiting human validation**, not complete or release-ready. Preserve that status in handoffs so another session cannot assume approval.
- Finish and evaluate the current feature before expanding its scope or starting unrelated additions. Any research backlog remains a set of proposals until deliberately selected for work.
- For each substantial milestone, compare plausible approaches and record the chosen responsibilities, data contracts, tradeoffs and acceptance checks before implementation. Keep abstractions proportionate to verified needs; do not grow a central coordinator or invent a universal framework merely to finish a feature quickly.
- Diagnose failures before patching them and fix the cause at the responsible layer. A workaround must have an explicit reason, limits and regression evidence; do not rely on incidental redraws, state resets or swallowed errors to make a flow appear to work.
- Verify integration assumptions against current primary documentation and focused probes. Distinguish confirmed behavior from inference, preserve useful research/decision evidence, and bring consequential product or architecture choices back to the maintainer. Never claim maximum performance, scalability or accuracy without appropriate evidence.

## Upstream engine upgrade

Expand Down
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,23 @@

User-visible changes to NX Library are recorded here. Entries are grouped by release, with the newest first. Engine changes also have their own [upgrade notes](docs/upstream-upgrades/README.md).

## 0.1.4.3 — 2026-11-12

### Added

- **Six interface languages and independent region preferences.** English, Italian, French, German, Spanish and Brazilian Portuguese, selected from the Mac automatically or in **Settings → Start-up → Language & region**. Dates, numbers and sizes use the selected region. Language is selected directly from a list; Regional formats explains its scope and previews dates, numbers and sizes. Game language stays separate. Known catalog genres translate locally without changing saved metadata. Supported Nlib descriptions are requested in the interface language, with cached descriptions reused across regions sharing a language and an explicitly labelled fallback when unavailable. Language changes preserve the visible page and reuse fresh metadata instead of repeating English searches; Switch 2 IDs are included in localized lookups. Translation resources and placeholders are checked in packaged apps.
- **Storage by game.** Settings → Storage lists each game's app, build cache and logs, with the largest caches first, including hidden games. **Delete cache** removes only that game's build cache after confirmation, preserving the app, original game files, saves and logs. A shared cache is explained before deletion; unavailable folders are labelled rather than shown as empty. Cleanup runs without blocking the interface and waits until builds finish. File sizes include hidden files, shared paths count once in totals, and free space refers to the selected Game apps volume.

### Fixed

- **Adding NSP, XCI, NSZ and XCZ files works with the newest engine.** With **Newest engine** at a recent nxnative, every package add stopped with an error about `configure_dotnet`, a function the engine removed. NX Library now reads packages with old and new engines alike.
- **Cancelling or quitting during a build stops the engine's tools.** The engine now runs each tool in its own session. NX Library gives it time to stop them, then stops anything left, so quitting mid-build no longer leaves a shader build or `xcodebuild` running in the background.
- **Saves are not replaced while a cloud download is unfinished.** If the engine's download of a cloud save was cut short, the next game start puts this Mac's save back. Import and restore wait for that start and say so.

### Changed

- **Updated nxnative to `8a5c5e7e`.** Building no longer needs .NET, so Setup has no .NET card and its downloader is gone. Upstream reports fixes for rendering, shaders, textures and memory across many games, including Ocarina of Time terrain and Star Fox scene changes, steadier movies and ProMotion full screen at 60 fps. Red Dead Redemption, TUNIC, both Ori games, Metroid Prime 4: Beyond, The Binding of Isaac: Rebirth, PRAGMATA, Diablo III, Diablo II: Resurrected and Nintendo Switch Sports Resort are newly playable. The Metal compiler remains **32023.922**. Every game translates its shaders again at its next build, and installed game apps keep their engine until rebuilt. NX Library starts games without the engine's own settings window, so the engine's new cloud-save question does not appear yet. See the [engine review](docs/upstream-upgrades/2026-11-12-79741184-8a5c5e7e-review.md).

## 0.1.4.2 — 2026-11-09

### Fixed
Expand Down
6 changes: 6 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,9 @@ Record user-visible changes under **Unreleased** in [CHANGELOG.md](CHANGELOG.md)
Keep the description focused on the resulting behaviour. Move entries into a
dated version section when that release is actually published; unreleased work
must not appear as an already available release.

## Interface translations

The shared source is `Sources/NXLibraryCore/Resources/Localizable.xcstrings`. It includes en, it, fr, de, es and pt-BR. Keep keys stable, preserve every typed placeholder, provide quantity variants, and leave product names, technical identifiers and user-provided content unchanged. Translation-only PRs should identify their language and whether a fluent speaker reviewed them.

Run `python3 scripts/check_localizations.py` and the publication regressions after editing the catalog. A development build also checks its compiled resources. The initial translations await maintainer validation; no external translation-hosting service is required.
3 changes: 2 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ import PackageDescription

let package = Package(
name: "NXLibrary",
defaultLocalization: "en",
platforms: [.macOS(.v13)],
products: [
.library(name: "NXLibraryCore", targets: ["NXLibraryCore"]),
.executable(name: "NXLibrary", targets: ["NXLibrary"]),
],
targets: [
.target(name: "NXLibraryCore", path: "Sources/NXLibraryCore"),
.target(name: "NXLibraryCore", path: "Sources/NXLibraryCore", resources: [.process("Resources")]),
.executableTarget(
name: "NXLibrary",
dependencies: ["NXLibraryCore"],
Expand Down
21 changes: 14 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,11 @@ Game files, keys and firmware are not provided. See [Legal and third-party notic

### Project status

**0.1.4.2 alpha.** Download the packaged app from [Releases](https://github.com/Bium23/NxLibrary/releases/latest), or [build it from source](#building-from-source).
**0.1.4.3 alpha.** Download the packaged app from [Releases](https://github.com/Bium23/NxLibrary/releases/latest), or [build it from source](#building-from-source).

Automated checks cover the application code, publication inputs, compilation and development-app packaging. They do not certify game compatibility. Changes are recorded in the [changelog](CHANGELOG.md), and the current checks are available under [Actions](https://github.com/Bium23/NxLibrary/actions/workflows/ci.yml).

The engine is pinned to `79741184`, with Ocarina of Time startup/memory/rendering improvements, Switch 2 Bluetooth controller support in rebuilt games, updated frame-rate profiles and cloud-save race protection, using Xcode 27.2 / Metal 32023.922. See the [engine upgrade notes](docs/upstream-upgrades/README.md).
The engine is pinned to `8a5c5e7e`: builds no longer need .NET, rendering and shader fixes across many games, newly playable titles such as Red Dead Redemption, TUNIC, Metroid Prime 4: Beyond and PRAGMATA, and safer stopping of builds and cloud-save downloads, using Xcode 27.2 / Metal 32023.922. See the [engine upgrade notes](docs/upstream-upgrades/README.md).

## Getting started

Expand All @@ -80,7 +80,6 @@ The engine is pinned to `79741184`, with Ocarina of Time startup/memory/renderin
|---|---|
| **Mac** | Apple silicon, macOS 13 or later. |
| **Xcode** | 27.2 or later, with the Metal compiler certified for the pinned engine. |
| **.NET** | .NET 10 SDK, used by the engine's extractor. |
| **Engine** | nxnative at the pinned commit. Setup can prepare the checkout; an existing folder can be chosen in **Settings → Engine**. |
| **Your files** | Your own supported game sources and keys, with the rights and permissions needed to use them. |

Expand Down Expand Up @@ -117,7 +116,7 @@ Packaged releases check this repository for app updates; no GitHub account is ne

Setup has two steps, **Get ready** and **Your games**.

**Get ready** shows the engine, build tools and keys. **Install all** handles the supported steps: the engine checkout, the certified Metal compiler and the official .NET installer. Xcode itself comes from the App Store; its licence and any system prompts remain your responsibility. Choose **Continue** to proceed; incomplete build requirements can be finished later, and existing game apps remain playable.
**Get ready** shows the engine, build tools and keys. **Install all** handles the supported steps: the engine checkout and the certified Metal compiler. The engine's tools are native, so .NET is no longer needed. Xcode itself comes from the App Store; its licence and any system prompts remain your responsibility. Choose **Continue** to proceed; incomplete build requirements can be finished later, and existing game apps remain playable.

**Your games** shows **Game apps**: where to keep existing nxnative games (`.app`) and install new builds. It checks the selected folder before reporting an empty library. Use **Change** to choose another folder, **Choose game file** for NSP, XCI, NSZ or XCZ, or **Choose a folder instead** for a source folder, including supported extracted inputs. A single detected title opens the existing build review; multiple titles require a choice. Selecting sources never starts a build by itself. Cancelling the picker stays on this page.

Expand Down Expand Up @@ -155,6 +154,12 @@ When you quit a game, NX Library comes back to the front, unless you had moved t

<p align="center"><strong>Quick access.</strong><br>Open the menu without leaving your library.</p>

### Language and region

The unreleased hotfix adds **English, Italiano, Français, Deutsch, Español and Português (Brasil)**. **Settings → Start-up → Language & region** follows the Mac automatically or lets you choose the app language and region separately. Changes apply immediately and are remembered. The **Regional formats** setting controls only date, number and size formats; **Game options → Language** continues to control each game independently.

Choose a language directly from its list. Known catalog genres are translated locally, without changing the saved metadata. Descriptions from Nlib are requested in the app language when supported, with cached descriptions shared between regions using the same language. Switching language reuses available artwork and credits; when those are fresh, only the localized description is requested. English remains available when a translated description cannot be found; descriptions, mod text and release notes from external sources are not automatically translated. Personal names, metadata choices, artwork and game settings are preserved.

### Add or rebuild a game

1. Open **Add game** and choose or drop a supported file or folder.
Expand Down Expand Up @@ -293,7 +298,7 @@ Before reporting a problem, review copied diagnostics and remove anything person
### Compatibility and limitations

- NX Library uses a manually pinned engine and checks its commit, working tree, CLI contract and Metal compiler before new builds. It does not follow upstream `main` automatically. **Settings → Engine → Newest engine** lets you choose `main` yourself before NX Library has tested it: an orange dot marks it, builds are recorded as untested, **Update** moves to a newer `main` when there is one, **Back to tested** returns to the pinned engine, and it is not offered when `main` needs a different Metal compiler.
- The current engine is `79741184` and certifies Metal `32023.922`. **Build anyway with an untested toolchain** requires explicit confirmation and marks the resulting build as untested. A successful launch does not turn it into a certified combination.
- The current engine is `8a5c5e7e` and certifies Metal `32023.922`. **Build anyway with an untested toolchain** requires explicit confirmation and marks the resulting build as untested. A successful launch does not turn it into a certified combination.
- Game compatibility depends on nxnative, the game version and the toolchain.
- Output follows the window/display; native 1440p/4K internal rendering is not supported. Render scale is 50–100% where the build supports it. MetalFX is spatial upscaling.
- Builds run one at a time. iOS/IPA output, automatic engine updates and notarisation are not currently provided.
Expand All @@ -304,14 +309,16 @@ The [upgrade notes](docs/upstream-upgrades/README.md) record each engine review

App data lives in `~/Library/Application Support/NXLibrary/`. Local game data uses `~/Library/Application Support/nxnative/<title ID>/`, with mods in its `mods` folder. Backups are stored under `NXLibrary/SaveBackups/<title ID>/`.

Storage can clear caches and logs and open the shared backups folder. **Remove Sources & Build Cache deletes the selected original source files**, while retaining the installed app and saves. Read that confirmation carefully; it differs from clearing a cache.
**Settings → Storage → By game** shows app, build cache and log sizes for every library entry, including hidden games, with the largest caches first. **Delete cache** permanently removes only the chosen game's build cache after confirmation. Its app, original game files, saves and logs stay in place; the next rebuild may take longer. Shared caches are identified, and their confirmation explains the effect on the other entries. Connect unavailable drives or check folder access, then choose **Recalculate**. Sizes describe file contents; actual space recovered can differ, and shared folders count once in totals. This addition is unreleased; the maintainer confirmed it works in Dev.

Storage can also clear all build caches or logs and open the shared backups folder. Cleanup runs without blocking navigation and is unavailable during a build or app update. **Remove Sources & Build Cache deletes the selected original source files**, while retaining the installed app and saves. Read that confirmation carefully; it differs from clearing a cache.

## Next steps

- **Simpler Settings** — Keep everyday options easy to find, with advanced controls grouped within each category.
- **In-app bug reporting** — Make it easier to report a problem directly from NX Library.
- **Broader game discovery** — Discover and launch games from Steam, CrossOver and the Mac App Store, alongside nxnative apps.
- **Languages** — NX Library in more languages than English.
- **Community translations** — Review and extend the initial six interface languages.
- **Better controller support** — Refine controller settings and offer more flexible button mapping.
- **Continued polish** — Fix bugs and improve navigation, feedback and visual details throughout the app.

Expand Down
3 changes: 2 additions & 1 deletion Sources/NXLibrary/Models/AppIconAppearanceMode.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import NXLibraryCore
import Foundation

public enum AppIconAppearanceMode: String, CaseIterable, Identifiable, Hashable {
Expand All @@ -10,5 +11,5 @@ public enum AppIconAppearanceMode: String, CaseIterable, Identifiable, Hashable
/// Light and Dark remain readable for existing preferences; today's artwork
/// has one colour variant and one monochrome variant.
public static let selectable: [Self] = [.auto, .mono]
public var label: String { self == .mono ? "Monochrome" : "Color" }
public var label: String { self == .mono ? L10n.text("Monochrome") : L10n.text("Color") }
}
22 changes: 11 additions & 11 deletions Sources/NXLibrary/Models/NXLibraryError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,27 +19,27 @@ public enum NXLibraryError: Error, LocalizedError {
public var errorDescription: String? {
switch self {
case .baseRequired:
return "Select a base game. Updates and DLC alone cannot be built."
return L10n.text("Select a base game. Updates and DLC alone cannot be built.")
case .missingSources:
return "The source files are missing. Attach or locate the original base, update and DLC files first."
return L10n.text("The source files are missing. Attach or locate the original base, update and DLC files first.")
case .missingTitleId:
return "The game has no title ID. Choose a valid NSP, XCI, NSZ or XCZ source."
return L10n.text("The game has no title ID. Choose a valid NSP, XCI, NSZ or XCZ source.")
case .missingKeys:
return "prod.keys is missing. Import it in Settings."
return L10n.text("prod.keys is missing. Import it in Settings.")
case .engineMissing:
return "The nxnative checkout was not found. Choose it in Settings → Engine."
return L10n.text("The nxnative checkout was not found. Choose it in Settings → Engine.")
case .environmentBlocked(let detail):
return "The build environment is incomplete: \(detail)"
return L10n.format("The build environment is incomplete: %@", [String(describing: (detail))])
case .incompatibleToolchain(let detail):
return "The toolchain is not certified: \(detail)"
return L10n.format("The toolchain is not certified: %@", [String(describing: (detail))])
case .buildAlreadyRunning:
return "A build is already running."
return L10n.text("A build is already running.")
case .appMissing(let path):
return "The app bundle is missing: \(path)"
return L10n.format("The app bundle is missing: %@", [String(describing: (path))])
case .launchFailed(let name):
return "macOS could not launch \(name)."
return L10n.format("macOS could not launch %@.", [String(describing: (name))])
case .noSelectedGame:
return "Select a game first."
return L10n.text("Select a game first.")
case .keyCheck(let reason, let game):
return "\(reason.what(game: game)) \(reason.next)"
}
Expand Down
Loading