This commit contains the latest updates from the generic Website template, which move the toolchain to Swift 6.4, gate analytics and structured data behind traits, and rework page routing: - Updated the Swift toolchain for all the package dependencies and the Website service to version 6.4. (345b305) - Adapted all the existing middlewares in the Infrastructure package to Swift 6.4. (26008df) - Moved test resource teardown in the Persistence and the Website library into defer blocks. (27984a9) - Gated analytics behind a trait and reworked structured data in the Infrastructure package. (c7d4769) - Enabled the Analytics trait in the Website service. (f6a6bbd) - Reworked page routing in the Website service. (d1cb2c1) - Gated the structured data features in the Infrastructure package behind a trait. (f0a8791) - Enabled the StructuredData trait of the Infrastructure package in the Website service. (bbfdeb3) - Fixed the asset pin and a build warning in the Dockerfile of the Website service. (6ed0f9b) The root README change in 345b305 was left out, as this project no longer carries that file. From d1cb2c1, the RootController rework was left out, as the prototype serves a session-aware landing page and routes its other pages through their own controllers; the view-event reporter was appended to the prototype's shared script instead. The prototype code was adapted to the stricter Swift 6.4 settings: `String(format:)` was swapped for safe formatting, the NoIndex middleware takes a `@concurrent` next handler, and the tests flagged by warnings-as-errors were tightened. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
44 lines
3.3 KiB
Markdown
44 lines
3.3 KiB
Markdown
# Localization
|
|
The server-side localization toolkit the platform's services build on: locale-explicit String Catalog lookups, `Accept-Language` negotiation, and the catalog-derived language list — with no dependencies beyond Foundation.
|
|
|
|
## Overview
|
|
| Role | Types |
|
|
| --- | --- |
|
|
| Lookup | `Localize`, a bundle-bound localizer that resolves a catalog key for an explicit locale |
|
|
| Negotiation | `Negotiate`, which picks the best supported language from an explicit request or an `Accept-Language` header per RFC 9110 |
|
|
| Languages | `LanguageList`, the supported and default languages a bundle's String Catalog defines |
|
|
| Diagnostics | `CatalogState`, the outcome of reading the catalog (`loaded`, `missing`, or `undecodable`) |
|
|
|
|
## Design rules
|
|
- **The String Catalog is the single source of truth.** Supported languages, the default language, and every string come from the bundle's `Localizable.xcstrings`, so adding a language is a translation-only change.
|
|
- **The locale is always explicit.** A server has no single "current" locale, so every lookup names the locale to resolve in; nothing reads process-wide locale state.
|
|
- **Raw `.xcstrings` parsing, for Linux parity.** The catalog is decoded from its JSON rather than through Foundation's compiled-catalog APIs, which are unavailable or non-functional on Linux. Consumers must `.copy` the resource verbatim (never `.process` it) so it ships as raw JSON everywhere. Only simple `stringUnit` values are decoded — plural and device variations are not.
|
|
- **Resolution never fails.** A missing entry falls back to the source-language string, then to the key itself; a missing or undecodable catalog degrades the language list to the default. Check `catalogState` at startup and warn when it is not `.loaded`.
|
|
- **Method structs.** `Localize` and `Negotiate` hold their lifetime-fixed configuration (the bundle) in `init` and take only per-call inputs in `callAsFunction`.
|
|
- **One decoded catalog per bundle.** Catalogs are immutable at runtime, so every `Localize`, `Negotiate`, and `LanguageList` bound to the same bundle and table shares one cached `StringCatalog`.
|
|
|
|
## Layout
|
|
Sources are split by visibility, then by kind, one type per file:
|
|
```
|
|
Sources/
|
|
├── Public/
|
|
│ ├── Enumerations/ CatalogState
|
|
│ ├── Methods/ Localize, Negotiate
|
|
│ └── Types/ LanguageList
|
|
└── Internal/
|
|
├── Protocols/ CatalogResolving, the seam between the public API and the catalog backend
|
|
└── Types/ StringCatalog (the cached .xcstrings decoder), LanguageRange
|
|
Tests/
|
|
├── Cases/ the test suites, mirroring the Sources/ layout
|
|
├── Catalogs/ the String Catalog fixture, copied verbatim so it loads on Linux
|
|
└── Utils/ the StubCatalog resolver and the suite Tag constants
|
|
```
|
|
|
|
## Testing
|
|
Every suite carries a tag for the kind of API it exercises — `.method` or `.type`, declared in `Tests/Utils/Extensions/Tag+Constants.swift` — so test plans and summaries can slice a run by kind. A new suite adopts the tag matching its subject, or adds one when none fits.
|
|
|
|
## Requirements
|
|
- Swift 6.4 toolchain (`swift-tools-version:6.4`).
|
|
- macOS 15, matching the sibling packages (the services deploy to Linux containers; the packages carry no UI platforms).
|
|
- No package dependencies — Foundation and Synchronization only.
|