title: How to localise strings that pre-dominantly consist of variables – efficiently as dev and intuitively as translator
body: <p>I have hundreds of dynamic strings, i.e. one or more variables exist within these string that are dynamically generated in code. For example, this is a string with anything in &lt;&gt; representing a variable whose value is unknown until the code is executed:</p>
  <p>&lt;Mostly cloudy&gt; with   to &lt;25°&gt; by &lt;2pm&gt;</p>
  <p>As these strings will be localised, ideally I’d depend on a .strings file to store them. Here’s the above example if I was to define it there:</p>
  <pre><code>/*
      One condition throughout an hourly range
      e.g. &lt;Mostly cloudy&gt; with &lt;temperatures&gt; &lt;rising&gt; to &lt;25°&gt; by &lt;2pm&gt;.
      
      Parameters:
      1- weather
      2- measurement point (default=temperature)
      3- measurement trajectory (upwards or downwards)
      4- measurement value
      5- time above value is reached
   */
  &quot;hourSeries_const&quot; = &quot;%@ with %@ %@ to %@ by %@.&quot;;
  </code></pre>
  <p>Thanks to <a href="https://stackoverflow.com/a/56445894/698971">https://stackoverflow.com/a/56445894/698971</a>, I created a String extension that returns the localised string with its arguments passed in:</p>
  <pre><code>/// Fetches a localised String Arguments
  ///
  /// - Parameter arguments: parameters to be added in a string
  /// - Returns: localized string
  public func localized(with arguments: [CVarArg]) -&gt; String {
      return String(format: self.localized, locale: nil, arguments: arguments)
  }
  </code></pre>
  <p>And getting the final string for the UI is as simple as calling:</p>
  <pre><code>let a = &quot;hourSeries_const&quot;.localized(with: [&quot;Mostly cloudy&quot;,&quot;temperatures&quot;,&quot;rising&quot;,&quot;24°&quot;,&quot;2pm&quot;])
  </code></pre>
  <p>But this isn’t perfect for a couple of reasons. The string in the .strings file won’t be reader-friendly. Comments are essential to understand what each variable represents. And then imagine a situation in which the variable order needs to be rearranged so that the string reads naturally in a language. This needs to be tracked somehow, and then I have to intervene in code too to ensure the order I pass in the arguments is changed accordingly.</p>
  <p>The alternative I thought of that may partially address this (but has its own issues – more on that later) is to move the strings into code. For example, have a func:</p>
  <pre><code>func hourSeries_const(weather:String, dataPoint:String, valueDirection:String, valueHighlight:String, highlightedValueTime:String) -&gt; String {
    return &quot;\(weather) with \(dataPoint) \(valueDirection) to \(valueHighlight) by \(highlightedValueTime).&quot;
  }
  </code></pre>
  <p>But with several languages to support, I’ll need to have a <code>switch</code> to choose between the different languages. This isn’t ideal as I was planning to send each translator their language file(s) to work with, i.e. it should only include their language’s strings. I could work around by adding a selector function that calls the selected language’s function:</p>
  <pre><code>func hourSeries_const(...) -&gt; String {
   switch language {
    case &quot;en&quot;: return hourSeries_const_en(...)
    case &quot;de&quot;: return hourSeries_const_de(...)
   }
  }
  </code></pre>
  <p>This is not the end of the world, but it does mean every time I add a new language, I’ll need to add a new case for every one of these functions pointing to the language’s corresponding function for the string.</p>
  <p>Is there an option that has the convenience of depending on .strings files but that offers the readability of descriptive variable names in strings for translators to work with?</p>