app-localization

Manage iOS/macOS .strings files in Tuist-based projects.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "app-localization" with this command: npx skills add tddworks/claude-skills/tddworks-claude-skills-app-localization

App Localization

Manage iOS/macOS .strings files in Tuist-based projects.

Project Structure

<ModuleName>/ ├── Resources/ │ ├── en.lproj/Localizable.strings # Primary language (English) │ ├── <locale>.lproj/Localizable.strings # Additional locales │ └── ... ├── Derived/ │ └── Sources/ │ └── TuistStrings+<ModuleName>.swift # Generated by Tuist └── Sources/ └── **/*.swift # Uses <ModuleName>Strings.Section.key

After editing .strings files, run tuist generate to regenerate type-safe accessors.

Complete Localization Workflow

Step 1: Identify Hardcoded Strings

Find hardcoded strings in Swift files:

Find Text("...") patterns with hardcoded strings

grep -rn 'Text("[A-Z]' <ModuleName>/Sources/ grep -rn 'title: "[A-Z]' <ModuleName>/Sources/ grep -rn 'label: "[A-Z]' <ModuleName>/Sources/ grep -rn 'placeholder: "[A-Z]' <ModuleName>/Sources/

Step 2: Add Translation Keys

Add keys to all language files:

en.lproj/Localizable.strings (primary):

/* Section description */ "section.key.name" = "English value"; "section.key.withParam" = "Value with %@";

Other locales (translate appropriately):

"section.key.name" = "<translated value>"; "section.key.withParam" = "<translated> %@";

Step 3: Generate Type-Safe Accessors

tuist generate

This creates Derived/Sources/TuistStrings+<ModuleName>.swift with accessors:

  • <ModuleName>Strings.Section.keyName (static property)

  • <ModuleName>Strings.Section.keyWithParam(value) (static function for %@ params)

See references/tuist-strings-patterns.md for detailed patterns.

Step 4: Update Swift Code

Replace hardcoded strings with generated accessors.

Pattern Mapping

Hardcoded Pattern Localized Pattern

Text("Title")

Text(<Module>Strings.Section.title)

Text("Hello, (name)")

Text(<Module>Strings.Section.hello(name))

title: "Submit"

title: <Module>Strings.Action.submit

placeholder: "Enter..."

placeholder: <Module>Strings.Field.placeholder

Example Transformations

Before:

Text("Settings") .font(.headline)

TextField("Enter your name", text: $name)

Button("Submit") { ... }

Text("Hello, (userName)!")

After:

Text(<Module>Strings.Section.settings) .font(.headline)

TextField(<Module>Strings.Field.namePlaceholder, text: $name)

Button(<Module>Strings.Action.submit) { ... }

Text(<Module>Strings.Greeting.hello(userName))

Handling Parameters and Plurals

String with parameter (key: "search.noResults" = "No results for "%@"" ):

// Before Text("No results for "(searchText)"")

// After Text(<Module>Strings.Search.noResults(searchText))

Conditional plurals:

// Keys: // "item.count" = "%d item" // "item.countPlural" = "%d items"

// Swift: let label = count == 1 ? <Module>Strings.Item.count(count) : <Module>Strings.Item.countPlural(count)

Multiple parameters (key: "message.detail" = "%@ uploaded %d files" ):

Text(<Module>Strings.Message.detail(userName, fileCount))

Step 5: Validate Changes

  • Build the project to catch missing keys

  • Run validation script to check consistency:

python scripts/validate_strings.py /path/to/<ModuleName>

AI-Powered Translation

When translating strings to non-English locales:

  • Read the English source string

  • Consider context from the key name (e.g., search.noResults = search UI)

  • Translate appropriately for the target locale:

  • zh-Hans: Simplified Chinese, formal but friendly

  • zh-Hant: Traditional Chinese

  • ja: Japanese, polite form (desu/masu style)

  • ko: Korean, polite form (hamnida/yo style)

  • de/fr/es/etc.: Appropriate regional conventions

  • Preserve all placeholders exactly (%@, %d, %ld, etc.)

Translation context by UI element:

  • Labels: Keep concise

  • Buttons: Action-oriented verbs

  • Placeholders: Instructive tone

  • Error messages: Helpful and clear

  • Confirmations: Clear consequences

Validation Scripts

Validate .strings Files

python scripts/validate_strings.py /path/to/<ModuleName>

Checks for:

  • Missing keys between languages

  • Duplicate keys

  • Placeholder mismatches (%@, %d, %ld)

  • Untranslated strings (value = English)

Sync Missing Translations

Report missing keys:

python scripts/sync_translations.py /path/to/<ModuleName> --report

Add missing keys as placeholders:

python scripts/sync_translations.py /path/to/<ModuleName> --sync

Key Naming Convention

Pattern: "domain.context.element" → <Module>Strings.Domain.Context.element

Domain-Focused Naming (User Mental Model)

Keys should reflect what the user is doing, not technical UI components:

User Mental Model Key Pattern Generated Accessor

"I'm looking at my profile" "profile.name"

Strings.Profile.name

"I'm testing a build" "betaBuild.whatToTest"

Strings.BetaBuild.whatToTest

"I'm adding a tester" "testerGroup.addTester"

Strings.TesterGroup.addTester

"Something went wrong with sync" "sync.error.failed"

Strings.Sync.Error.failed

Good vs Bad Examples

Bad (Technical) Good (Domain-Focused)

button.save

profile.save

field.email

registration.email

placeholder.search

appSelector.searchPlaceholder

error.network

sync.connectionFailed

label.title

settings.title

alert.confirm

build.expireConfirm

Structure by Feature/Screen

Organize keys by the feature or screen where they appear:

/* Profile Section */ "profile.title" = "Profile"; "profile.name" = "Name"; "profile.save" = "Save Changes"; "profile.saveSuccess" = "Profile updated";

/* Beta Builds */ "betaBuild.title" = "Beta Builds"; "betaBuild.whatToTest" = "What to Test"; "betaBuild.submitForReview" = "Submit for Review"; "betaBuild.expireConfirm" = "Expire this build?";

/* Tester Groups */ "testerGroup.create" = "Create Group"; "testerGroup.addTester" = "Add Tester"; "testerGroup.empty" = "No testers yet";

This mirrors how users think: "I'm in Beta Builds, submitting for review" → betaBuild.submitForReview

.strings File Format

/* Comment describing the section */ "key.name" = "Value"; "key.with.parameter" = "Hello, %@!"; "key.with.number" = "%d items"; "key.with.multiple" = "%1$@ has %2$d items";

Rules:

  • Keys must be unique within a file

  • Values are UTF-8 encoded

  • Escape quotes with backslash: "

  • Line ends with semicolon

  • Use positional parameters (%1$@, %2$d) when order differs between languages

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

appstore-info-generator

No summary provided by upstream source.

Repository SourceNeeds Review
General

ios-ux-prototype

No summary provided by upstream source.

Repository SourceNeeds Review
General

template-skill

No summary provided by upstream source.

Repository SourceNeeds Review
General

ios-app-scaffold

No summary provided by upstream source.

Repository SourceNeeds Review