skillby ericfitz

update_json_localization_file

Update a JSON localization file with additions and deletions while preserving formatting. Use when modifying i18n translation files or syncing localization keys.

Installs: 0
Used in: 1 repos
Updated: 1d ago
$npx ai-builder add skill ericfitz/update_json_localization_file

Installs to .claude/skills/update_json_localization_file/

# Update JSON Localization File

Safely update a JSON localization file by adding, updating, or removing keys while preserving proper formatting.

## Inputs

- **file_path**: Path to the JSON file to update
- **additions**: Dictionary of `{key: value}` pairs to add or update
- **deletions**: List of keys to remove
- **preserve_formatting**: Boolean (default: `true`) - maintain existing key order vs. sort alphabetically

## Output

Return a summary object:

```json
{
  "file_path": "src/assets/i18n/es-ES.json",
  "keys_added": 5,
  "keys_updated": 3,
  "keys_deleted": 2,
  "total_keys": 450
}
```

## Process

### Step 1: Read Current File

Read the existing file content. If the file doesn't exist, start with an empty object `{}`.

```
file_path: src/assets/i18n/es-ES.json
```

Handle errors gracefully:
- File not found → Create new file
- Permission denied → Report error
- Invalid JSON → Report error with line number if possible

### Step 2: Parse JSON

Parse the JSON content while preserving structure:
- Maintain nested object hierarchy
- Track existing keys for add vs. update distinction

### Step 3: Apply Deletions

For each key in the deletions list:
- Support dot notation for nested keys: `"about.title"` → delete `json.about.title`
- If key doesn't exist, skip silently (idempotent)
- If deleting a key leaves an empty parent object, keep the empty object

```
deletions: ["obsolete.key1", "deprecated.feature"]
```

**Deletion logic for nested keys:**

```
Key: "about.opensource.paragraph3"

Before:
{
  "about": {
    "opensource": {
      "paragraph1": "...",
      "paragraph2": "...",
      "paragraph3": "..."
    }
  }
}

After:
{
  "about": {
    "opensource": {
      "paragraph1": "...",
      "paragraph2": "..."
    }
  }
}
```

### Step 4: Apply Additions

For each key-value pair in additions:
- Support dot notation: `"about.newKey"` → `json.about.newKey = value`
- If key exists: update value, count as "updated"
- If key is new: add it, count as "added"
- Create intermediate objects as needed for nested keys

```
additions: {
  "about.title": "Acerca de TMI",
  "newSection.newKey": "New Value"
}
```

**Addition logic for nested keys:**

```
Key: "newSection.subSection.key"
Value: "Hello"

Before:
{
  "existingKey": "..."
}

After:
{
  "existingKey": "...",
  "newSection": {
    "subSection": {
      "key": "Hello"
    }
  }
}
```

### Step 5: Sort Keys (Optional)

If `preserve_formatting` is `false`, sort all keys alphabetically at each level of nesting.

**Sorting rules:**
- Case-sensitive alphabetical sort
- Sort recursively at every nesting level
- Numbers sort before letters in ASCII order

If `preserve_formatting` is `true`:
- Keep existing keys in their original order
- Add new keys at the end of their respective objects (or in sorted position among new keys)

### Step 6: Write File

Write the updated JSON back to the file with proper formatting.

**Formatting requirements:**
- 2-space indentation
- UTF-8 encoding
- Final newline at end of file
- No trailing whitespace on lines
- Unix line endings (`\n`)

**Safe write process:**

1. Create backup: `{file_path}.bak`
2. Write to temporary file: `{file_path}.tmp`
3. Rename temporary file to target (atomic operation)
4. Preserve original file permissions

```bash
# Conceptual process
cp file.json file.json.bak
write_json > file.json.tmp
mv file.json.tmp file.json
```

## Error Handling

### File Errors

| Error | Behavior |
|-------|----------|
| File not found | Create new file with additions only |
| Permission denied | Return error, do not modify |
| Disk full | Return error, backup preserved |
| Invalid JSON | Return error with details |

### Key Errors

| Error | Behavior |
|-------|----------|
| Delete non-existent key | Skip silently (idempotent) |
| Invalid key format | Return error |
| Key collision (add + delete same) | Delete wins, then add |

## Examples

### Add New Translations

```
Input:
  file_path: "src/assets/i18n/es-ES.json"
  additions: {
    "common.save": "Guardar",
    "common.cancel": "Cancelar",
    "errors.network": "Error de red"
  }
  deletions: []

Output:
  {
    "file_path": "src/assets/i18n/es-ES.json",
    "keys_added": 3,
    "keys_updated": 0,
    "keys_deleted": 0,
    "total_keys": 453
  }
```

### Update Existing Translation

```
Input:
  file_path: "src/assets/i18n/fr-FR.json"
  additions: {
    "common.save": "Sauvegarder"
  }
  deletions: []

Output:
  {
    "file_path": "src/assets/i18n/fr-FR.json",
    "keys_added": 0,
    "keys_updated": 1,
    "keys_deleted": 0,
    "total_keys": 450
  }
```

### Remove Obsolete Keys

```
Input:
  file_path: "src/assets/i18n/de-DE.json"
  additions: {}
  deletions: ["deprecated.oldFeature", "legacy.button"]

Output:
  {
    "file_path": "src/assets/i18n/de-DE.json",
    "keys_added": 0,
    "keys_updated": 0,
    "keys_deleted": 2,
    "total_keys": 448
  }
```

### Mixed Operations

```
Input:
  file_path: "src/assets/i18n/ja-JP.json"
  additions: {
    "new.feature.title": "新機能",
    "common.ok": "はい"
  }
  deletions: ["old.feature.title"]

Output:
  {
    "file_path": "src/assets/i18n/ja-JP.json",
    "keys_added": 1,
    "keys_updated": 1,
    "keys_deleted": 1,
    "total_keys": 450
  }
```

### Create New File

```
Input:
  file_path: "src/assets/i18n/new-LANG.json"
  additions: {
    "app.title": "Application Title",
    "app.description": "Description"
  }
  deletions: []

Output:
  {
    "file_path": "src/assets/i18n/new-LANG.json",
    "keys_added": 2,
    "keys_updated": 0,
    "keys_deleted": 0,
    "total_keys": 2
  }
```

## Implementation Notes

1. **Atomic writes**: Always use temp file + rename to prevent corruption on failure.

2. **Backup retention**: Keep only the most recent `.bak` file. Consider timestamped backups for critical operations.

3. **Key counting**: For nested structures, count leaf keys only (keys with string values, not object parents).

4. **Dot notation edge cases**:
   - Key contains literal dot: Not supported (use nested structure)
   - Empty key segment: Invalid (`"a..b"`)
   - Leading/trailing dots: Invalid (`".key"`, `"key."`)

5. **Concurrent access**: This operation is not atomic across multiple callers. Use external locking if needed.

6. **Large files**: For files over 1MB, consider streaming JSON parser. Standard i18n files are typically under 100KB.

7. **Validation**: After writing, optionally re-read and parse the file to verify it's valid JSON.

Quick Install

$npx ai-builder add skill ericfitz/update_json_localization_file

Details

Type
skill
Author
ericfitz
Slug
ericfitz/update_json_localization_file
Created
4d ago