Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Are there any plans to support ranges in units? #33

Closed
ribanez7 opened this issue Mar 20, 2023 · 10 comments
Closed

Are there any plans to support ranges in units? #33

ribanez7 opened this issue Mar 20, 2023 · 10 comments

Comments

@ribanez7
Copy link
Contributor

Currently it is possible to pass float, integer, Decimal or Ratio, but would it be a possibility to pass a range? Or maybe this should be responsibility of Cldr.Number.to_range_string ?

If we include it in Cldr.Number.to_range_string, maybe it can be passed as an option, like the currency one. Why not allow an option for unit, if there is an option for currency?

And in case that should be responsibility of Cldr.Unit, I could try to do a POC.

@kipcole9
Copy link
Collaborator

@ribanez7, thanks for the suggestion. I'm not sure I completely understand what you're suggesting. I think what you are saying is something like:

iex> Cldr.Unit.new(:kilogram, 100..1000)

Is that the idea? I'm interested but I can see some challenges.

  • There aren't any specific localised formats or templates in CLDR for formatting unit ranges - I'm not sure what Cldr.Unit.to_string/2 would emit for such a range. Do you have some thoughts?
  • Would these range units be expected to support math operations? Like the ones in Cldr.Math
  • Serialising range units would be difficult - I don't think they could be supported in ex_cldr_unit_sql.

I'm curious about the use case you have in mind. Can you share an example?

@ribanez7
Copy link
Contributor Author

Sure. I am using a custom unit (person), to show company sizes. The japanese case gives us some juice since it also changes the way a range is formatted (using tilde instead of dash).

So given this implementation:

  unit_localization(:person, "ja", :long,
    nominative: %{
      one: "{0} 人",
      other: "{0} 人"
    },
    display_name: "人"
  )

Let's say I want something like: 1-10 people, or even with a current unit, hour => 1-2 hr.

I would like something like:

iex> MyApp.Cldr.Unit.to_string!(MyApp.Cldr.Unit.new!(:hour, 1..2), [unit: :hour, style: :long, locale: :en])     
"1-2 hours"

But that implies calling MyApp.Cldr.Number.to_range_string(1..2, locale: :en, format: :long) and appending the Unit.to_string! result to it, calculated maybe with the last number in the range.

The japanese case I was talking about would result in:

MyApp.Cldr.Unit.to_string!(MyApp.Cldr.Unit.new!(:person 1..2), [style: :long, locale: :ja])     
"1〜2人"

@ribanez7
Copy link
Contributor Author

I can't come up with examples of it using math operations.

@kipcole9
Copy link
Collaborator

kipcole9 commented Mar 20, 2023

Thanks for the example, I understand better now. I think there is a way to do a unit version analogous to Date.Range called Unit.Range with the caveat that both units in the range would need to be the same unit type.

I am working on a series of updates for CLDR 43 data that will launch in about 3 weeks. Is that manageable timing for you?

@kipcole9
Copy link
Collaborator

I can also implement Enumerable for a Unit.Range too.

@ribanez7
Copy link
Contributor Author

Yep, that will work perfectly. For the meantime I have a helper function to do it "the kind-of-hardcoded-way", by calculating both things separately (the number.to_range_string and the unit.to_string) and placing them together just with a concat.
To extend the use of it in more languages I'll wait for the implementation 👍🏼 , now I'm using my function just for controlled situations.

kipcole9 added a commit that referenced this issue Mar 21, 2023
* Adds Cldr.Unit.Range module and type
* Adds Enumeration implementation for Cldr.Unit.Range.t
* Adds Inspect implementation for Cldr.Unit.Range.t

Unit Range formatting will be implemented next in this
module. I can't be implemented in Cldr.Number because
that would create a circular dependency.

This commit is targeted for ex_cldr_units version
3.16.0 to coincide with CLDR 43 in April.
@kipcole9
Copy link
Collaborator

I've closed this issue for now. Still on track for shipping in a couple of weeks. When everything across all the cldr projects is merged it'll be easier for you to test for your own use cases. For now, here's an example:

iex> {:ok, range} = Cldr.Unit.Range.new(Cldr.Unit.new!(:gram, 1), Cldr.Unit.new!(:gram, 5))
iex> Cldr.Unit.to_string(range, locale: :ja)
{:ok, "1~5 グラム"}

@ribanez7
Copy link
Contributor Author

Many thanks @kipcole9 , that's awesome.

@kipcole9
Copy link
Collaborator

You're welcome. As a bonus, Cldr.Unit.Range.t implements the Enumeration protocol:

iex> range = Cldr.Unit.Range.new!(Cldr.Unit.new!(:gram, 1), Cldr.Unit.new!(:gram, 5))
iex> Enum.to_list(range)
[Cldr.Unit.new!(:gram, 1), Cldr.Unit.new!(:gram, 2), Cldr.Unit.new!(:gram, 3),
 Cldr.Unit.new!(:gram, 4), Cldr.Unit.new!(:gram, 5)]

@ribanez7
Copy link
Contributor Author

Yess, I've seen that going through the code, brilliant 👍🏼

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants