elixir-cldr / cldr_units

Unit formatting (volume, area, length, ...) functions for the Common Locale Data Repository (CLDR)
Other
16 stars 13 forks source link

Is there a way to get just the localised unit/metric? #11

Closed ghost closed 4 years ago

ghost commented 4 years ago

👋

Is there a way to get only the unit like App.Cldr.Unit.to_string(:meter) # => "Meter"?

kipcole9 commented 4 years ago

Interesting idea - I'll look into it. It's not as straight forward as you might think since the underlying data is actually a series of templates. For example {0} meter and {0} meters for English singular and plural. And if it has an SI prefix its actually two templates that have to be merged: milli {0} and {0} meter. Its even more complicated when it's a compound unit like cubic milliampere light year.

A solution may have to be as editing out the numeric value. I'll think on this today.

I'm a little bit curious - what's the use case you're looking to solve?

ghost commented 4 years ago

A solution may have to be as editing out the numeric value. I'll think on this today.

That's roughly what I'm doing right now, it's probably missing some edge-cases but seems to work for de and en locales for the time being:

case App.Cldr.Unit.to_string(1, unit: unit) do
  {:ok, "1" <> unit} -> String.trim(unit)
  _other -> nil
end

I'm a little bit curious - what's the use case you're looking to solve?

I'm using units in table headers like TEMPERATURE (DEGREE CELSIUS) or ENERGY (KILOWATT HOUR) or CO2 (PART PER MILLION). And I also have a place in the app where I want to style the unit and the numeric value differently so I'm splitting them there as well (not sure if it is the right approach though):

<span class="big bright"><%= value %></span> <!-- 30 -->
<span class="small dimmed"><%= unit %></span> <!-- °C -->
kipcole9 commented 4 years ago

Ahhh, make sense, good use case. What you actually have as headings there isn't the unit though - its the unit category ie Temperature. I can certainly derived the unit category but I'm not sure there are translations for these in CLDR (I will check).

Would something like this work for you? I think this can be produced reasonably easily (will experiment on the weekend)

Temperature Energy
23°C 23h⋅kW
23°F 43h⋅kW

This short form of output comes from Cldr.Unit.to_string unit, style: :narrow

NB: For complex units the formatting can be improved and I'm working on it.

ghost commented 4 years ago

Would something like this work for you?

Oh, I didn't think of moving the unit into the table cells instead of the header. Yes, that would totally work.

kipcole9 commented 4 years ago

Cool, I think that gives me a chance. Even if you have to use Gettext for translating the headings at least the units can work.

So basically my work this weekend is to find a better way to format complex units like kilowatt hours.

Anything else that would help this case?

kipcole9 commented 4 years ago

I will also be working on an Ecto data type to store units with their unit types in Postgres this weekend. Don't know if thats helpful to you or not.

ghost commented 4 years ago

Even if you have to use Gettext for translating the headings at least the units can work.

Sorry, forgot to mention, yes, I'm translating the unit categories via gettext, and only use Cldr to get the units.

Anything else that would help this case?

Not directly related, but maybe having a way to get the "splitted" unit would help with my second use-case where I want to style the value and the unit differently:

{:ok, {value, unit}} = App.Cldr.Unit.to_string(value, unit: unit, split: true)

so that then I can put them in separate <span> tags.

kipcole9 commented 4 years ago

Interesting challenge - I'll see what I can do :-)

kipcole9 commented 4 years ago

I've push a couple of commits to master. Here's the changelog:

Bug Fixes

Bug Fixes

Usage

Now you can say:

iex> Cldr.Unit.to_iolist Cldr.Unit.new!(:kilowatt_hour, 123), MyApp.Cldr 
{:ok, ["123", " kilowatt-hours"]}

Note that there is no guarantee that the number element is first. And there is no guarantee that there are only two elements in the list. But if you are sure of what the shape of the result will be you can:

iex> [number, unit_name] = Cldr.Unit.to_iolist! Cldr.Unit.new!(:kilowatt_hour, 123), MyApp.Cldr 
["123", " kilowatt-hours"]

iex> number
"123"

iex> unit_name
" kilowatt-hours"

Test it out

And you should be good to go .....

Let me know if everything is ok on your end and I'll plan a release to hex.

ghost commented 4 years ago

@kipcole9 thank you!

Let me know if everything is ok on your end and I'll plan a release to hex.

Sure! I'm sorry I won't be able to test it today, but I will definitely do it tomorrow.

ghost commented 4 years ago

Let me know if everything is ok on your end and I'll plan a release to hex.

@kipcole9 thank you! Works great!

kipcole9 commented 4 years ago

I've published ex_cldr_units version 3.1.0. Was a good exercise and the refactoring helps separate concerns too. Let me know if there is anything that would help you use case?

Closing now, thanks for the collaboration.