0

I'm working on implementing translations in my app, however the format of my translations is not usable for me. I made a shell script that uses jq to try to modify this array, but I cannot get the output that I desire.

The JSON I get from my service looks something like this.

{
  "result": {
    "terms": [
      {
        "term": "title",
        "translation": {
          "content": "Welcome to {{user}}"
        }
      },
      {
        "term": "car",
        "translation": {
          "content": {
              "one": "car",
              "other": "cars"
          }
        }
      }
    ]
  }
}

The output that I want is something like this.

{
  "title": "Welcome to {{user}}",
  "car_one": "car",
  "car_other": "cars",
}

I've managed to strip away the uneeded parts of my objects, but I can't figure out how to append something to they key, e.g. turning "car" into "car_one". Or actually just adding the keys properly to the array.

This is currently where I'm at https://jqplay.org/s/P6KIEVX5sWp

2 Answers 2

1

Probably not the most efficient solution, but this oughta work and is kinda readable:

.result.terms
| map(
    (select(.translation.content | type == "object")
        | .term as $term | .translation.content | to_entries[] | .key |= "\($term)_\(.)"),
    (select(.translation.content | type == "string")
        | { key: .term, value: .translation.content })
)
| from_entries

Or with if-then-else:

.result.terms
| map(
    if .translation.content | type == "object" then
        .term as $term | .translation.content | to_entries[] | .key |= "\($term)_\(.)"
    else
        { key: .term, value: .translation.content }
    end
)
| from_entries

Cleverly place (and name) the variable and you get down to:

.result.terms
| map(.term as $key
    | .translation.content
    | if type == "object" then
         to_entries[] | .key |= "\($key)_\(.)"
    else
        { $key, value: . }
    end
)
| from_entries

Even more concise by combining the optional/error suppression operator with the alternative operator:

.result.terms
| map(.term as $key
    | .translation.content
    | (to_entries[] | .key |= "\($key)_\(.)")? // { $key, value: . }
)
| from_entries

Or, if you prefer (so many possibilities):

.result.terms
| map(
    .term as $key
    | .translation.content as $value | $value
    | (to_entries[] | .key |= "\($key)_\(.)")? // { $key, $value }
)
| from_entries

"\($key)_\(.)" is string interpolation and equivalent to ($key + "_" + .)

Sign up to request clarification or add additional context in comments.

Comments

0

The requirements aren't entirely clear to me, but the following does follow the logic of your approach and does produce the required output:

   .result
   | [.terms[]
      | if .translation.content|type == "string" then {title: .translation.content}
        else .term as $term
        | .translation
        | (.content|keys) as $keys
        | ([$keys[] as $key | {($term + "_" + $key): .content[$key]}] | add) 
        end ]
  | add

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.