<turbo-stream action="append" target="posts_list"><template>    <div class="postbit" id="178641" data-post-id="178641">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="kip" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/kip/120/1440_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  kip
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>ex_cldr Core Team</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<h2><a name="p-178641-ex_cldr_calendars-version-190httpshexpmoackagesex_cldr_calendars190-published-1" class="anchor" href="#p-178641-ex_cldr_calendars-version-190httpshexpmoackagesex_cldr_calendars190-published-1" aria-label="Heading link" rel="nofollow"></a><a href="https://hex.pm/oackages/ex_cldr_calendars/1.9.0" rel="nofollow">Ex_cldr_calendars version 1.9.0</a> published</h2>
<p>The is minor release that primarily fixes several bugs in duration calculations. Did someone mention data and time are hard? The changelog is <a href="https://github.com/elixir-cldr/cldr_calendars/blob/v1.9.0/CHANGELOG.md" rel="nofollow">here</a>.</p>
<h4><a name="p-178641-enhancements-2" class="anchor" href="#p-178641-enhancements-2" aria-label="Heading link" rel="nofollow"></a>Enhancements</h4>
<p>Three relevant features are added:</p>
<ol>
<li>
<p><code>Cldr.Calendar.Duration.new/1</code> support for <code>Date.Range.t</code> and for <code>CalendarInterval.t</code>. <code>CalendarInterval</code> is defined by <a class="mention" href="/u/wojtekmach" rel="nofollow">@wojtekmach</a>’s excellent <a href="https://hex.pm/packages/calendar_interval" rel="nofollow">calendar_interval</a> library.</p>
</li>
<li>
<p><code>Cldr.Calendar.plus/2</code> to support adding a duration to a <code>Calendar.date</code>. Support for adding a duration to a <code>Calendar.datetime</code> is not yet provided.</p>
</li>
<li>
<p><code>String.Chars</code> support for <code>Cldr.Calendar.Duration</code> makes it easy to output localised strings representing a duration.</p>
</li>
</ol>
<h4><a name="p-178641-examples-3" class="anchor" href="#p-178641-examples-3" aria-label="Heading link" rel="nofollow"></a>Examples</h4>
<pre data-code-wrap="elixir"><code class="lang-elixir"># Create a duration, then add it back to the beginning date
# and check the round trip is correct.
iex&gt; {:ok, duration} = Cldr.Calendar.Duration.new(~D[2019-01-01], ~D[2019-12-31])
{:ok,
 %Cldr.Calendar.Duration{
   day: 30,
   hour: 0,
   microsecond: 0,
   minute: 0,
   month: 11,
   second: 0,
   year: 0
 }}

iex&gt; Cldr.Calendar.plus ~D[2019-01-01], duration
~D[2019-12-31]

# Create a duration from a CalendarInterval
iex&gt; use CalendarInterval
iex&gt; Cldr.Calendar.Duration.new ~I"2020-01/12"
{:ok,
 %Cldr.Calendar.Duration{
   day: 30,
   hour: 0,
   microsecond: 0,
   minute: 0,
   month: 11,
   second: 0,
   year: 0
 }}

# Support the String.Chars protocol
to_string Cldr.Calendar.Duration.new!(~D[2020-01-01], ~D[2020-03-01]) ==
"2 months"

iex&gt; to_string Cldr.Calendar.Duration.new!(~D[2020-01-01], ~D[2020-03-04]) ==
"2 months and 3 days"

iex&gt; to_string Cldr.Calendar.Duration.new!(~D[2020-01-01], ~D[2021-03-04]) ==
"1 year, 2 months and 3 days"

iex&gt; to_string Cldr.Calendar.Duration.new!(~D[2020-01-01], ~U[2021-03-04 01:02:03.0Z]) ==
"1 year, 2 months, 3 days, 1 hour, 2 minutes and 3 seconds"
</code></pre> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="178641" data-batch-url="/posts/batch_likers">
                        4
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/ex-cldr-common-locale-data-repository-cldr-functions-for-elixir/17350/42">Post #41</a>
	                </div>
	            </div>
              <div id="likers-container-178641" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="178641"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #41"></div>
  </section>
</div>
    <div class="postbit" id="179402" data-post-id="179402">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="kip" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/kip/120/1440_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  kip
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>ex_cldr Core Team</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>This weeks release bring you <a href="https://hex.pm/packages/ex_cldr_dates_times/2.5.0" rel="nofollow">ex_cldr_dates_times version 2.5.0</a>.  As usual here is the <a href="https://github.com/elixir-cldr/cldr_dates_times/blob/master/CHANGELOG.md" rel="nofollow">changelog</a> and the <a href="https://github.com/elixir-cldr/cldr_dates_times" rel="nofollow">github repo</a>.</p>
<p>This release reinforces my emerging view that developing these CLDR-based libraries is:</p>
<ul>
<li>
<p>30% understanding the structure of the CLDR data, the nuances of which there are many and marvelling at how smart the people that build and maintain <a href="https://cldr.unicode.org" rel="nofollow">CLDR</a> are.</p>
</li>
<li>
<p>30% distilling a functionally very rich set of data into an api design that is approachable and easy to use for 90% of cases with enough flexibility to use the another 8% in a straight forward manner (there are always a few small parts that I omit for my own sanity, and maybe the library users too).</p>
</li>
<li>
<p>30% on documentation and tests</p>
</li>
<li>
<p>10% on writing code.</p>
</li>
</ul>
<h4><a name="p-179402-datetime-interval-formatting-1" class="anchor" href="#p-179402-datetime-interval-formatting-1" aria-label="Heading link" rel="nofollow"></a>Date/Time Interval formatting</h4>
<p>This release adds formatting of date, time and datetime intervals.  Intervals can be two date/time/datetimes or a <code>Date.Range</code> or if you use the fabulous <a href="https://hex.pm/packages/calendar_interval" rel="nofollow">calendar_interval</a> library then a <code>CalendarInterval</code> can also be used.</p>
<p>The cool thing about formatting intervals is collapsing common date/time elements into a readable format for every configured locale.  This is helpful whether you use one locale or many.</p>
<h4><a name="p-179402-date-examples-2" class="anchor" href="#p-179402-date-examples-2" aria-label="Heading link" rel="nofollow"></a>Date Examples</h4>
<pre data-code-wrap="elixir"><code class="lang-elixir"># Same month and year
iex&gt; Cldr.Interval.to_string ~D[2020-01-01], ~D[2020-01-31]
{:ok, "Jan 1 – 31, 2020"}

# Same year but different months
iex&gt; Cldr.Interval.to_string ~D[2020-01-01], ~D[2020-02-11]
{:ok, "Jan 1 – Feb 11, 2020"}

# Standard formats :short, :medium and :long are defined
iex&gt; Cldr.Interval.to_string ~D[2020-01-01], ~D[2020-01-31], format: :long
{:ok, "Wed, Jan 1 – Fri, Jan 31, 2020"}

# Of course localised ....
iex&gt; Cldr.Interval.to_string ~D[2020-01-01], ~D[2020-01-31], locale: "th" 
{:ok, "1–31 ม.ค. 2020"}

# Including other number systems
iex&gt; Cldr.Interval.to_string ~D[2020-01-01], ~D[2020-01-31], locale: "th", number_system: :thai
{:ok, "๑–๓๑ ม.ค. ๒๐๒๐"}

# Date ranges can be used:
iex&gt; Cldr.Interval.to_string Date.range(~D[2020-01-01], ~D[2020-02-11])                        
{:ok, "Jan 1 – Feb 11, 2020"}

# As can the very cool calendar intervals
iex&gt; use CalendarInterval
iex&gt; Cldr.Interval.to_string ~I"2020-02-01/06-30"                        
{:ok, "Feb 1 – Jun 30, 2020"}

iex&gt; Cldr.Interval.to_string ~I"2020-01-01/31"                           
{:ok, "Jan 1 – 31, 2020"}

iex&gt; Cldr.Interval.to_string ~I"2020-02-01 00:00/10:05"
{:ok, "Feb 1, 2020, 12:00:00 AM – 10:05:00 AM"}
</code></pre> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="179402" data-batch-url="/posts/batch_likers">
                        3
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/ex-cldr-common-locale-data-repository-cldr-functions-for-elixir/17350/43">Post #42</a>
	                </div>
	            </div>
              <div id="likers-container-179402" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="179402"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #42"></div>
  </section>
</div>
    <div class="postbit" id="180214" data-post-id="180214">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="kip" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/kip/120/1440_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  kip
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>ex_cldr Core Team</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Introducing <a href="https://hex.pm/packages/ex_cldr_calendars_composite" rel="nofollow">ex_cldr_calendars_composite</a> which allows composition of multiple calendars at different points of the time continuum. A small but interesting project for a Saturday afternoon.</p>
<p>The <a href="https://en.wikipedia.org/wiki/Proleptic_Gregorian_calendar" rel="nofollow">Gregorian Proleptic calendar</a> is the most common calendar implementation (including Elixir’s Calendar module) and its behaviour is correct for the majority of contemporary uses. It is explicitly required by <a href="https://en.wikipedia.org/wiki/ISO_8601" rel="nofollow">ISO8601</a>.</p>
<p>However the fact that it represents dates before the introduction of the Gregorian calendar introduces inaccuracies in dates expressed before its introduction in a given territory. The Gregorian calendar was introduced starting on Friday, 15 October 1582 in the Papal States and was still being introduced in the 20th century with Russia adopting it (for non religious purposes) between 1918-1920 with parts of Romania, Greece, Serbia and Yugoslavia around the same period.</p>
<p><a href="https://hex,pm/packages/ex_cldr_calendars_composite" rel="nofollow">ex_cldr_calendars_composite</a> supports composing two or more calendars to more correctly specify dates before the introduction of the Gregorian calendar.</p>
<h3><a name="p-180214-example-composite-calendar-for-england-1" class="anchor" href="#p-180214-example-composite-calendar-for-england-1" aria-label="Heading link" rel="nofollow"></a>Example composite Calendar for England</h3>
<p>England (it is then colonies) introduced the Gregorian calendar on September 14th, 1752. This can be configured as:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">defmodule England do
  use Cldr.Calendar.Composite,
    calendars: ~D[1752-09-14],
    # The :base_calendar is optional and this is the default
    base_calendar: Cldr.Calendar.Julian. 
end
</code></pre>
<p>As a result we can now treats dates as normal and have them respect the transition.</p>
<h3><a name="p-180214-composed-calendar-examples-2" class="anchor" href="#p-180214-composed-calendar-examples-2" aria-label="Heading link" rel="nofollow"></a>Composed calendar examples</h3>
<p>Using our example for <code>England</code>, dates now reflect the Julian calendar before September 14th, 1752 and the Gregorian calendar on or after it. This has some expected but unusual results. For example:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir"># September 1752 is 11 days "shorter" at the transition
iex&gt; Cldr.Calendar.England.days_in_month 1752, 9  
19

# And the full year is also shorter as a result
iex&gt; Cldr.Calendar.England.days_in_year 1752    
355
</code></pre>
<p>In all other respects, composite calendars implement the <code>Calendar</code> and  <code>Cldr.Calendar</code> behaviours.</p>
<h3><a name="p-180214-a-more-complex-example-3" class="anchor" href="#p-180214-a-more-complex-example-3" aria-label="Heading link" rel="nofollow"></a>A more complex example</h3>
<p>More complex compositions are possible. Consider that Egypt used the <a href="https://en.wikipedia.org/wiki/Coptic_calendar" rel="nofollow">Coptic calendar</a> from about 238 BCE. The Julian calendar was introduced in approximately 30 BCE. And the Gregorian calendar in 1875. This can be approximated with:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">defmodule Cldr.Calendar.Composite.Egypt do
  use Cldr.Calendar.Composite,
    calendars: [
      ~D[-0045-01-01 Cldr.Calendar.Julian],
      ~D[1875-09-01]
    ],
    base_calendar: Cldr.Calendar.Coptic
end
</code></pre>
<p>A Coptic calendar implementation is also available as <a href="https://hex.pm/packages/ex_cldr_calendars_coptic" rel="nofollow">ex_cldr_calendars_coptic</a>.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="180214" data-batch-url="/posts/batch_likers">
                        4
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/ex-cldr-common-locale-data-repository-cldr-functions-for-elixir/17350/44">Post #43</a>
	                </div>
	            </div>
              <div id="likers-container-180214" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="180214"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #43"></div>
  </section>
</div>
    <div class="postbit" id="189804" data-post-id="189804">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="tmbb" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  tmbb
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p><a class="mention" href="/u/kip" rel="nofollow">@kip</a> I’ve restarted working on my translation library based ICU messages. I’ve found that your implementation of the CLDR message format works great. I’ll publish it as soon as I have something useful, which should include the following:</p>
<ul>
<li>Translations should be cached in an efficient way, like compiling translations into raw functions (which would be the most efficient way possible) or using parsed ICU messages and storing them in something like <code>:persistent_term</code></li>
<li>It should be possible to edit translations at runtime</li>
<li>Based on the above, for Phoenix apps, there should be a plugin that allows you to click on an untranslated/translated string and edit it in place (possibly opening a new web page), and the new translation should be available on the next page reload 8or even forcing a page reload after the translation)</li>
<li>Unlike you, I’m not too keen on using an external web service to edit translations (unless is something you can self-host in development so that you can use it in the way I described above)</li>
</ul> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="189804" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/ex-cldr-common-locale-data-repository-cldr-functions-for-elixir/17350/45">Post #44</a>
	                </div>
	            </div>
              <div id="likers-container-189804" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="189804"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #44"></div>
  </section>
</div>
    <div class="postbit" id="189821" data-post-id="189821">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="kip" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/kip/120/1440_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  kip
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>ex_cldr Core Team</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Glad you’re back on this <img src="https://forum.elixirforum.com/images/emoji/apple/slight_smile.png?v=15" title=":slight_smile:" class="emoji" alt=":slight_smile:" loading="lazy" width="20" height="20"></p>
<p>My current implementation only serves to prove out the parser and renderer. Definitely not a full implementation as you point out.  It why I was advocating for splitting out the <code>.pot</code> parsing separately from <code>Gettext</code> so it could be a general message serialisation format.</p>
<p>My original thinking was that a backend could be one in which messages are baked into code (like Gettext), or kept at runtime (like <code>:persistent_term</code>) or managed in a web service and cached. I think different use cases suggest different approaches.</p>
<p>Anyway, more than happy to adjust <code>ex_cldr_messages</code> to fit in with the work you’re doing.  I’ve been “aggressively monitoring” the <a href="https://github.com/unicode-org/message-format-wg" rel="nofollow">MessageFormat Working Group</a> which is a collaboration to define the evolution of message localisation and all of the big players are participating. But recent pace of progress suggests thats going to take some time to mature.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="189821" data-batch-url="/posts/batch_likers">
                        1
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/ex-cldr-common-locale-data-repository-cldr-functions-for-elixir/17350/46">Post #45</a>
	                </div>
	            </div>
              <div id="likers-container-189821" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="189821"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #45"></div>
  </section>
</div>
    <div class="postbit" id="189835" data-post-id="189835">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="tmbb" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  tmbb
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="kip" data-post="46" data-topic="17350">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/kip/48/1440_2.png" class="avatar"> kip:</div>
<blockquote>
<p>It why I was advocating for splitting out the <code>.pot</code> parsing separately from <code>Gettext</code> so it could be a general message serialisation format.</p>
</blockquote>
</aside>
<p>I already have a .po parser that’s implemented outside of gettext and can parse a .po file into a list of <code>%Translation{}</code> which can be used by my implementation. You can then use Poedit or a similar program to edit those files.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="189835" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/ex-cldr-common-locale-data-repository-cldr-functions-for-elixir/17350/47">Post #46</a>
	                </div>
	            </div>
              <div id="likers-container-189835" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="189835"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #46"></div>
  </section>
</div>
    <div class="postbit" id="189965" data-post-id="189965">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="kip" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/kip/120/1440_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  kip
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>ex_cldr Core Team</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I published a small update to <a href="https://hex.pm/packages/ex_cldr_messages" rel="nofollow">ex_cldr_messages</a> primarily to fix a warning on Elixir 1.11 but also to support later versions of <a href="https://hex.pm/packages/ex_cldr_units" rel="nofollow">ex_cldr_units</a> and friends.</p>
<p>Back to your original message and design objectives and how <code>ex_cldr_messages</code> might fit in:</p>
<ul>
<li>
<p><code>Cldr.Message.format/2</code> operates totally at runtime, parsing and interpreting the format and returning a string</p>
</li>
<li>
<p><code>Cldr.Message.Parser.parse/1</code> parses a format and returns list that can be serialised safely and interpreted at runtime. Translations could be stored internally in this format.</p>
</li>
<li>
<p><code>Cldr.Message.Interpreter.format/3</code> takes the output from <code>Cldr.Message.Parser.parse/1</code> and interprets it in the context of a binding (a Keyword list) and returns an <code>io_list</code>. Which of course can easily be processed into a binary if required.</p>
</li>
</ul>
<p>There is a macro form of <code>format/1</code> defined in a backend CLDR module that parses at compile time and performs some basic checks on bindings (where possible). This is an optimisation of limited use at the moment since this doesn’t support runtime localisation.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="189965" data-batch-url="/posts/batch_likers">
                        1
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/ex-cldr-common-locale-data-repository-cldr-functions-for-elixir/17350/48">Post #47</a>
	                </div>
	            </div>
              <div id="likers-container-189965" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="189965"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #47"></div>
  </section>
</div>
    <div class="postbit" id="190026" data-post-id="190026">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="tmbb" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  tmbb
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>You can explore the latest version of Mezzofanti here: <a href="https://github.com/tmbb/mezzofanti" class="inline-onebox" rel="noopener nofollow ugc">GitHub - tmbb/ex_i18n: Experimental translation library for Elixir · GitHub</a></p>
<p>Currently it supports only a gettext backend (that it, it supports translations supplied as gettext files, even though the messages themselves use the ICU message format).</p>
<aside class="quote no-group" data-username="kip" data-post="48" data-topic="17350">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/kip/48/1440_2.png" class="avatar"> kip:</div>
<blockquote>
<p><code>Cldr.Message.format/2</code> operates totally at runtime, parsing and interpreting the format and returning a string</p>
</blockquote>
</aside>
<p>Currently I don’t have much use for this, but I might ad dit in the future. My rationale is that it’s not possible to translate a string that isn’t a static string marked as translatable in the source, so all translatable strings should be wrapped ina  ,macro and available at compile-time. This is different from gettext, where one can feed it dynamic strings, which will be translated according to the <code>.po</code> files. This is a requirement for packages like ecto, which can’t access the dependent application’s Gettext backend. However, because my Mezzofanti library is able to translate strings in dependencies (this was actually the main design criterion for my library), being able to handle dynamic strings is not as useful.</p>
<aside class="quote no-group" data-username="kip" data-post="48" data-topic="17350">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/kip/48/1440_2.png" class="avatar"> kip:</div>
<blockquote>
<p><code>Cldr.Message.Parser.parse/1</code> parses a format and returns list that can be serialised safely and interpreted at runtime. Translations could be stored internally in this format.</p>
</blockquote>
</aside>
<p>That is what I’m doing now. I’m currently embedding these lists in the code, but I can add them to a persistent term with little work and probably no relevant performance impact. I’m not doing this right now because I’m trying to reduce the amount of moving parts, but I have plans for adding it in the future.</p>
<aside class="quote no-group" data-username="kip" data-post="48" data-topic="17350">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/kip/48/1440_2.png" class="avatar"> kip:</div>
<blockquote>
<p>This is an optimisation of limited use at the moment since this doesn’t support runtime localisation.</p>
</blockquote>
</aside>
<p>I’m supplying the locale through the process dictionary.</p>
<p>This module illustrates a some interesting features (explained in the comments):</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">defmodule Mezzofanti.Fixtures.ExampleModule do
  use Mezzofanti
  # Not that I don't need to require or impor a Mezzofanti backend here.
  # I just use the Mezzofanti library, and once a backend is configured
  # it will automatically become aware of these messages
  # (even if the messages exist in a different application)

  def f() do
    # A simple static translation
    translate("Hello world!")
  end

  def g(guest) do
    # A translation with a variable.
    # This translation contains a context, possibly to disambiguate it
    # from a similar string which should be translated in a different way.
    # Mezzofanti will keep equal strings with different contexts separate.
    translate("Hello {guest}!", context: "a message", variables: [guest: guest])
  end

  def h(user, nr_photos) do
    # A more complex translation with two variables and plural forms.
    # It also defines a different domain.
    translate("""
    {nr_photos, plural,
      =0 {{user} didn't take any photos.}
      =1 {{user} took one photo.}
      other {{user} took # photos.}}\
    """,
      domain: "photos",
      variables: [
        user: user,
        nr_photos: nr_photos
      ])
  end
end
</code></pre>
<p>The following commands will create a <code>priv/mezofanti/</code> dir for the locale data:</p>
<pre><code class="lang-plaintext">mix mezzofanti.extract
mix mezzofanti.new_locale pt-PT
mix mezzofanti.merge
</code></pre>
<p>This will result in:</p>
<pre><code class="lang-plaintext">priv/
  mezzofanti/
    pt-PT/
      LC_MESSAGES/
        default.po
        photos.po
    default.pot
    photos.pot
</code></pre>
<p>The Mezzofanti and Cldr backends should be created and added to the apps’ config. Mezzofanti expects a single global Mezzofanti backend, so that you can centralize the translations of several applications/dependencies in the same place (this is a quastionable choice, but again, it was the main design goal of this library).</p>
<p>Like gettext, Mezzofanti reads the locale from the process dictionary. There are <code>Mezzofanti.set_locale()</code> and <code>Mezzofanti.get_locale()</code> for that. And also my favourite function for testing, the function <code>Mezzofanti.with_locale(locale, func)</code>, which sets the locale, executes the <code>func</code> and then resets the old locale.</p>
<p>For example:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">iex&gt; alias Mezzofanti.Fixtures.ExampleModule
Mezzofanti.Fixtures.ExampleModule

iex&gt; ExampleModule.f()
["Hello world!"]

iex&gt; ExampleModule.f() |&gt; to_string()
"Hello world!"

iex&gt; ExampleModule.g("tmbb") |&gt; to_string()
"Hello tmbb!"

iex&gt; ExampleModule.h("kip", 2) |&gt; to_string()
"kip took 2 photos."

iex&gt; ExampleModule.h("kip", 1) |&gt; to_string()
"kip took one photo."

iex&gt; ExampleModule.h("kip", 0) |&gt; to_string()
"kip didn't take any photos."

iex&gt; Mezzofanti.with_locale("pt-PT", fn -&gt; ExampleModule.h("kip", 0) |&gt; to_string() end)
"kip não tirou fotografias nenhumas."

iex&gt; Mezzofanti.with_locale("pt-PT", fn -&gt; ExampleModule.h("kip", 1) |&gt; to_string() end)
"kip tirou uma fotografia"

iex&gt; Mezzofanti.with_locale("pt-PT", fn -&gt; ExampleModule.h("kip", 2) |&gt; to_string() end)
"kip tirou 2 fotografias"
</code></pre>
<p>Mezzofanti also contains two “fake” locales for pseudoloalization. Pseudolocalization is a process of automatically replacing latin characters by similar foreign characters (like characters that are visually similar or contain diacritics not present in English) and extending words with extra characters so that they ar longer than the originals. This produces still readable strings, helps detect places where strings in your application haven’t been translated and helps detect places where you don’t have space for longer strings.</p>
<p>The “pseudo” locale provides pseudolocalization for simple text:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">iex&gt; Mezzofanti.with_locale("pseudo", fn -&gt; ExampleModule.h("kip", 2) |&gt; to_string() end)
"ǩıƥ~ ťøøǩ~ 2 ƥȟøťøš~~."

iex&gt; Mezzofanti.with_locale("pseudo", fn -&gt; ExampleModule.h("kip", 1) |&gt; to_string() end)
"ǩıƥ~ ťøøǩ~ øñê~ ƥȟøťø~."
</code></pre>
<p>The “pseudo_html” provides pseudolocalization for HTML text. It preserves HTML tags and HTML entities, while localizing the rest of the text. In the first line below, you can see how “normal” pseudolocalization is not sufficient for HTML:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">iex&gt; Mezzofanti.with_locale("pseudo", fn -&gt; ExampleModule.i() |&gt; to_string() end)        
"Ťȟıš~ ɱêššàğê~~ ċøñťàıñš~~ &lt;šťȓøñğ&gt;ȟťɱĺ~~~~ ťàğš&lt;/šťȓøñğ&gt;~~~~ &amp;àɱƥ~; ñàšťÿ~ šťüƒƒ~..."

iex&gt; Mezzofanti.with_locale("pseudo_html", fn -&gt; ExampleModule.i() |&gt; to_string() end)
"Ťȟıš~ ɱêššàğê~~ ċøñťàıñš~~ &lt;strong&gt;ȟťɱĺ~ ťàğš~&lt;/strong&gt; &amp;amp; ñàšťÿ~ šťüƒƒ~..."
</code></pre> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="190026" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/ex-cldr-common-locale-data-repository-cldr-functions-for-elixir/17350/49">Post #48</a>
	                </div>
	            </div>
              <div id="likers-container-190026" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="190026"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #48"></div>
  </section>
</div>
    <div class="postbit" id="190031" data-post-id="190031">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="kip" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/kip/120/1440_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  kip
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>ex_cldr Core Team</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Thats all very cool.  <code>ex_cldr</code> and friends also use the process dictionary for the locale too.  Do you have any thoughts on how we might synchronise the <code>gettext</code>, <code>mezzofanti</code> and <code>ex_cldr</code> locales?  In <code>ex_cldr</code> I built in awareness of <code>gettext</code> locales to make interoperability easier but that’s not a very scaleable solution.</p>
<p><code>ex_cldr_messages</code> needs to know the locale for when it localises number formats, dates, units, …  By default it uses the locale in the process dictionary (or a system default) but that risks being out of sync with Mezzofanti.</p>
<p>Looks like I know what I’m doing this weekend!</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="190031" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/ex-cldr-common-locale-data-repository-cldr-functions-for-elixir/17350/50">Post #49</a>
	                </div>
	            </div>
              <div id="likers-container-190031" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="190031"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #49"></div>
  </section>
</div>
    <div class="postbit" id="190036" data-post-id="190036">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="tmbb" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  tmbb
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="kip" data-post="50" data-topic="17350">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/kip/48/1440_2.png" class="avatar"> kip:</div>
<blockquote>
<p>Do you have any thoughts on how we might synchronise the <code>gettext</code> , <code>mezzofanti</code> and <code>ex_cldr</code> locales?</p>
</blockquote>
</aside>
<p>We don’t need to synchronize anything. Your <code>Cldr.Message.format/3</code> function accepts a locale as an option in the options list. I simply read my <code>:mezzofanti_locale</code> key from the process dictionary and feed that as an argument to <code>Cldr.Message.format/3</code>, which is totally unaware I’m getting the locale from the process dictionary. Everything is decoupled and Cldr doesn’t need to be aware of anything.</p>
<p>The key module is this:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">defmodule Mezzofanti.Translator do
  @moduledoc false
  alias Mezzofanti.Config

  @doc false
  def __translate__(hash, variables, translation) do
    locale = Mezzofanti.get_locale() || Cldr.default_locale().cldr_locale_name

    case Config.backend() do
      nil -&gt;
        # Interpolate the message with the default locale
        Cldr.Message.format_list(translation.parsed, variables, locale: locale)

      module -&gt;
        module.translate_from_hash(hash, locale, variables, translation)
    end
  end
end
</code></pre>
<p>All translations in Mezzofanti go through the <code>__translate__()</code> function. This function reads the locale from the process and feeds it to the <code>module.translate_from_hash/4</code> function, which then feeds it into <code>Cldr.Message.format()</code> (the code where this happens is not as nice to show because it’s built inside a macro, but you get the idea)</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="190036" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/ex-cldr-common-locale-data-repository-cldr-functions-for-elixir/17350/51">Post #50</a>
	                </div>
	            </div>
              <div id="likers-container-190036" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="190036"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #50"></div>
  </section>
</div>
</template></turbo-stream><turbo-stream action="replace" target="load-more-container"><template><div id="load-more-container" class="load-more-container">
    <a class="load-more-button" data-turbo-stream="true" href="/topics/17350/load_more?page=6">Load more posts (70 remaining)</a>
</div></template></turbo-stream>