Localization Style Guide — Vulture
Moved from vulture-ios/LOCALIZATION_STYLE.md
Purpose
Section titled “Purpose”This is the single source of truth for voice, tone, and terminology across all of Vulture’s localizations.
- English is the canonical source language. Every other language is translated from harmonized English — never from Dutch.
- Used in two phases: (1) harmonize the existing English + Dutch, (2) translate into German, Spanish, Czech, Italian, Slovenian, and Polish.
- Scope: every user-facing string in the String Catalogs (
.xcstrings) across all targets.
Voice — constant (who Vulture is)
Section titled “Voice — constant (who Vulture is)”Vulture speaks like a knowledgeable co-pilot: it knows aviation, assumes you do too, and gets you the information fast.
- Warm and friendly, never patronizing. The audience is pilots. Be approachable without dumbing things down or over-explaining the basics of the domain.
- Clear over clever. No puns, idioms, or wordplay — they fragment across seven languages and slow translation down.
- Direct and active. Address the user as “you”, use the active voice, lead with the action or the fact.
- Concise where it counts. People check weather quickly, often pre-flight or on the move. Short by default; spend words only where they help — errors, empty states, onboarding.
Tone — varies by context (how the voice bends)
Section titled “Tone — varies by context (how the voice bends)”| Context | Tone |
|---|---|
| Labels, titles, buttons | Neutral, functional, short. A few words. |
| Errors & failures | Calm, helpful, solution-oriented. No blame, no alarm. Say what happened and what to do next. |
| Empty states & onboarding | Warm and inviting. A little personality is welcome here. |
| Confirmations & success | Brief and genuine. Don’t over-celebrate routine actions. |
Form of address — locked
Section titled “Form of address — locked”Informal, in every language. Vulture is on a first-name basis with its users.
| Language | Informal form |
|---|---|
| English | you |
| Dutch | je / jij |
| German | du |
| Spanish | tú |
| Czech | ty (tykání) |
| Italian | tu |
| Slovenian | ti |
| Polish | ty |
Avoid the formal register everywhere (u / Sie / usted / vy / Lei / vi / Pan–Pani), including in imperatives and system-style messages.
Spelling & vocabulary
Section titled “Spelling & vocabulary”- English variant: US English (favorite, color, center, analyze). Locked — the existing strings are already uniformly US, so no normalization is needed (see the spelling note in the Glossary).
- Avoid English loanwords in Dutch where a natural Dutch term exists — except established aviation terms (see glossary), which keep their canonical form in every language.
Mechanics
Section titled “Mechanics”Capitalization — sentence case everywhere (buttons, titles, labels, alerts). Sentence case scales cleanly across all seven languages; Title Case is an English-only construct that reads oddly or is simply wrong in Dutch, German, and others.
- Exception: German capitalizes all nouns (grammatically required) — that is correct, not a violation.
- Proper nouns and the brand name “Vulture” are always capitalized.
Punctuation
- No period after standalone labels, titles, or button text.
- Full sentences (alerts, body text, multi-sentence empty states) take normal punctuation.
- Exclamation marks are rare. Warm is not loud — at most one per screen, and almost never in routine UI.
Numbers & units
- Aviation units stay in their standard abbreviations: kt, ft, hPa / inHg, SM / m / km. Don’t translate or expand them.
- Respect each locale’s decimal separator and number formatting through the catalog — never hardcode it into the string.
Plurals
- Always use the catalog’s “vary by plural” — never hand-write “item(s)” or append “(s)”. This matters for the four-form (Polish, Czech) and dual-form (Slovenian) languages coming later.
Glossary
Section titled “Glossary”Locked terminology lives here so translation works from one fixed vocabulary. The tables below are populated from the real strings during the glossary step — see the harmonization prompt.
Do not translate (aviation canon — fixed in every language)
Section titled “Do not translate (aviation canon — fixed in every language)”METAR, TAF, NOTAM, QNH, QFE, ATIS, and standard unit abbreviations (kt, ft, hPa, inHg, SM). Brand name: Vulture. Extend from the actual strings during the glossary step.
Canonical terms — LOCKED
Section titled “Canonical terms — LOCKED”One term per concept, applied consistently across the whole app. This is the authoritative list; the evidence (every variant found, with keys) is in “Variants found” below. Locked 2026-06-16; not yet applied to the strings — harmonization will normalize the variants to these terms.
| Concept | Canonical EN term | Rationale |
|---|---|---|
| A point within a task/route | turnpoint (one word) | Most common form; gliding usage. Replaces “turn point” and “turning point”. Distinct from a stored waypoint. |
| A stored navigation point (from CUP files) | waypoint | Already consistent. In task editing, decide per string whether it means the task point (→ turnpoint) or adding a stored waypoint (stays waypoint). |
| The list of recorded/imported flights | flight log (two words) | Dominant UI label form. Replaces “logbook” and “Saved flights”. |
| The user’s home airfield | home base (two words) | Two-word form used in every on-screen label. Replaces one-word “homebase” in copy. (Keys keep homebase.) |
| An airfield / landing site | airfield | Used everywhere bar one body string (“airports”). “aerodrome”/“airstrip” never appear. |
| Permanently destroying a record | delete | Reserved for destroying data. Resolve soaringspot.competitions.delete (shows “Remove”) to “Delete”. |
| Taking an item off a view/list (not destroying it) | remove | Kept only for view/collection removal (e.g. “Remove from map”). |
| Emptying transient state (task, filter, leg) | clear | Already consistent; locked apart from delete/remove. |
| Throwing away unsaved work | discard | Already consistent; locked apart from delete/clear. |
| The GPS trace and live heading | track | Locked to “track” for everything; “flight path” is dropped. |
| Re-fetching data | update | “Reload” converges into “Update” (“Update terrain”). |
| iCloud synchronization | sync | A distinct action from a UI refresh; kept separate from update. |
Spelling: US English (locked). Brand name: Vulture (do-not-translate). Form of address: informal in every language (see Form of address above).
Dutch canonical terms — LOCKED
Section titled “Dutch canonical terms — LOCKED”Most concepts map straight from English, but a few need an explicit Dutch term because Dutch does not split the same way. Applied during harmonization (2026-06-16).
| English concept | Dutch term | Note |
|---|---|---|
| The flown GPS trace | vluchtpad | Replaces the old mix of “de vlucht” / “pad” / “(geoptimalizeerde) route”. The optimized trace is “geoptimaliseerd vluchtpad”. |
| Live heading / direction | richting | English “track” is overloaded (trace + heading); Dutch keeps them apart. Drops the “track” loanword (“Huidige track” → “Huidige richting”, “Reële track” → “Reële richting”). |
| flight log | logboek | Replaces the English-spelled “logbook”/“Logbook” that had crept into the Dutch strings. |
| turnpoint | keerpunt | Already consistent in Dutch. |
Note: existing Dutch spelling quirks (e.g. “geoptimalizeerde” for standard “geoptimaliseerde”) are left as-is — spelling normalization is a separate pass.
Proposed canonical terms — inspection, pending review
Section titled “Proposed canonical terms — inspection, pending review”Built by scanning the English values across all nine .xcstrings catalogs.
Nothing below has been applied; these are proposals to lock before harmonization.
Variants cite representative key(s) as evidence.
| Concept | Proposed canonical EN | Variants found (with keys) | Rationale |
|---|---|---|---|
| A point within a task/route | turnpoint (one word) | turnpoint ×18 (task.button.turnpoint.add, task.label.point = “Turnpoint”, task.label.turnpoints.goto); turn point (flight.label.event.turnpoint = “Turn point confirmation”); turning point (task.edit.label.select.message); also called waypoint inside task editing (task.edit.button.delete = “Delete waypoint”, task.edit.button.add = “Add existing waypoint”, task.edit.button.rename = “Rename waypoint”) | One-word “turnpoint” is by far the most common; matches gliding usage. Keep distinct from stored waypoints (next row) — the in-task waypoint strings are the main ambiguity to resolve. |
| A stored navigation point (from CUP files) | waypoint | waypoint/waypoints ×46, consistent (map.settings.waypoints.title, file.label.import.cup.waypoints, settings.label.waypoints) | Already consistent. Concept differs from an in-task turnpoint; keeping the two words separate prevents conflation. |
| The list of recorded/imported flights | flight log (two words) | flight log ×~9 (sidebar.label.flights.log, flight.label.logbook = “Flight log”, selection.button.flights, Watch general.flights.title); logbook (one word) (wifi.label.send.complete.flight, bluetooth.label.send.complete.flight, buetooth.label.notification.download.message); Saved flights (Watch general.flights.description) | “Flight log” dominates the UI labels; “logbook” and “Saved flights” describe the same destination. |
| The user’s home airfield | home base (two words) | home base ×3 (settings.homebase.label.title = “Your home base”, task.menu.center.homebase = “Go to home base”, settings.label.waypoint.home); homebase (one word) (Metar Widget metar.intent.description) | Two-word form is used in every on-screen label; the single occurrence of “homebase” is in body copy. (Keys keep homebase — not user-facing, leave as-is.) |
| An airfield / landing site | airfield | airfield ×6 (inflight.airport.label.name = “Airfield”, inflight.airport.button.goto = “Navigate to airfield”, settings.homebase.label.waypoint.style.gliding = “Gliding airfield”); airports (inflight.airport.label.note = “The airports and frequencies…”) | “Airfield” is the term everywhere except one body string; “aerodrome”/“airstrip” never appear. |
| Permanently destroying a record | delete | delete ×22 (flight/task/waypoint/file actions); remove for the same intent (soaringspot.competitions.delete = “Remove”) | Reserve “Delete” for destroying data. Note the key/value mismatch: soaringspot.competitions.delete shows “Remove” — decide whether that action is a delete or a list-removal. |
| Taking an item off a view/list (not destroying it) | remove | remove (flight.button.deletefrommap = “Remove from map”) | Distinct from delete; keep “Remove” only for view/collection removal. |
| Emptying transient state (task, filter, leg) | clear | clear ×7 (common.button.clear, inflight.cleartask.title = “Clear task?”, flight.button.clearleg, flight.button.clearinfringements, soaringspot.competitions.clear) | Already consistent; listed to lock it apart from delete/remove. |
| Throwing away unsaved work | discard | discard ×4 (common.button.discard, inflight.label.stop.message, Watch inflight.discard) | Already consistent; locked apart from delete/clear. |
| The flown GPS trace and live heading | track (LOCKED) | “flight path” (map.settings.flightpath = “Show flight path”, map.settings.coloredtrack = “Show colored flight path”, map.settings.coloredtrack.description); “track” (map.settings.flighttrack = “Show current track”, inflight.label.info.track.current = “Current track”); mixed: map.settings.optimizedpath = “Show optimized track” | Locked to “track” for everything — “flight path” is dropped. Harmonize “flight path” → “track” (e.g. “Show track”, “Optimized track”, “Colored track”, “Current track”). |
| Re-fetching data | update (LOCKED) | “Update” (common.button.update, file.button.update, task.edit.button.update = “Update the task”); “Reload” (flight.button.reloadterrain = “Reload terrain”) | “Reload” converges into “Update” (flight.button.reloadterrain → “Update terrain”). iCloud sync (migration.label.description) stays a separate term — it is a different action, not a UI refresh. |
Spelling — LOCKED to US English. The strings are already uniformly US (favorite, color, colored, optimized); no UK/US split was found, so no normalization is required. “Favorite”/“Favorites” is consistent across App and Watch.
Brand name — RESOLVED: the app is “Vulture”. Every brand mention in the strings is “Vulture” (×28); “Eagle” appears in no string. This guide has been corrected from “Eagle” to “Vulture” throughout. (“Eagle” is only the SPM package name — never user-facing.) “Vulture” is in the do-not-translate set below.
Do not translate — found in the strings (keep verbatim in every language)
Section titled “Do not translate — found in the strings (keep verbatim in every language)”Only terms that actually appear in the catalogs are listed (TAF, NOTAM, QFE, ATIS, SM, QFF do not appear and are omitted).
| Term | Note |
|---|---|
| METAR | ×9 (general.raw.metar = “RAW METAR”, qnh.description, metar.intent.description). Aviation canon. |
| QNH | ×1 (qnh.description). Aviation canon. (qnh.name source value is “QHN” — a typo; out of scope here, flagged for the harmonization step.) |
| ICAO | ×3 (inflight.airport.label.icao = “ICAO”). Aviation canon. |
| FLARM | ×7 (task.button.share.flarm). Proper noun / collision-avoidance system. |
| IGC | ×5 (NSLocationAlwaysUsageDescription, file types). Flight-log file standard. |
| CUP | ×4 (task.button.share.cup = “CUP file”). SeeYou waypoint file format. |
| GPS | ×3 (flight.info.label.gps). Standard abbreviation. |
| BLE | ×1 (bluetooth.label.devices.slow = “Downloading over BLE…”). Bluetooth Low Energy. |
| Wi-Fi | ×3 (wifi.label.title = “Send to Wi-Fi device”). Keep the hyphenated trademark form. |
| AGL / AMSL / MSL / FL | Altitude references (inflight.label.info.height.agl, airspace.labels.amsl = ”%@ AMSL”, airspace.labels.fl = “FL %d”). Aviation canon. |
| kt, ft, km, nm, hPa, inHg | Unit abbreviations (settings.labels.unit.*). Never translate or expand. |
| Vulture | ×28. App/brand name (see brand note above). |
| SkySight | ×22 (skysight.*). Third-party weather service. |
| SoaringSpot | ×1 (tasks.soaringspot). Third-party competition service (note casing: “SoaringSpot”). |
| OurAirports | ×2 (inflight.airport.label.note). Third-party data source. |
| Mapbox | ×5 (settings.label.mapboxtelemetry). Map SDK / vendor. |
| iCloud | ×1 (migration.label.description). Apple service name. |
| Photo Library | ×1 (map.settings.photosvisible.description). Apple feature name. |
- Don’t use different words for the same concept (see canonical terms, once locked).
- Don’t stack jargon where a plain word works — but don’t strip established aviation terms either.
- Don’t write humor or cultural references that won’t survive translation.
- Don’t hardcode user-facing text outside the catalogs.
App Store metadata
Section titled “App Store metadata”Same voice as the app — knowledgeable, clear, warm — but a persuasive tone, because the goal shifts from helping an existing user to convincing a prospect to download. Stay concrete and competent: pilots see through hype, so specifics (data sources, coverage, refresh speed, METAR/TAF/NOTAM support) sell better than superlatives. Keep the same restraint as the rest of the guide — no “best aviation app ever”, exclamation marks stay rare.
Metadata lives outside the .xcstrings catalogs. It’s managed in App Store Connect (or fastlane deliver, under metadata/<locale>/) and localized as its own stream alongside the catalog strings.
| Field | Tone | Limit (chars) |
|---|---|---|
| App name | The brand. | 30 |
| Subtitle | One concrete promise. | 30 |
| Promotional text | A timely hook; editable without app review. | 170 |
| Description | Persuasive lead, then concrete: what it does, what data, which sources. | 4000 |
| Keywords | Not a tone surface — ASO research per market. | 100 |
- Keywords are researched, not translated. Find what pilots in each market actually search for; never translate the English keyword list literally.
- Character limits bite in the long languages — the 30-char subtitle most of all. DE/PL/CS run 20–35% longer, so rewrite to fit rather than translate.
- Localize from harmonized English, following the same form-of-address and spelling rules as the app.
