diff --git a/lib/aprsme/convert.ex b/lib/aprsme/convert.ex
index 80381c0..c38eb7c 100644
--- a/lib/aprsme/convert.ex
+++ b/lib/aprsme/convert.ex
@@ -9,4 +9,47 @@ defmodule Aprsme.Convert do
@spec speed(number(), :knots, :mph) :: float()
def speed(value, :knots, :mph), do: Float.round(value * 1.15077945, 2)
+
+ # Weather unit conversions
+ @doc """
+ Converts Fahrenheit to Celsius
+ """
+ def f_to_c(fahrenheit) when is_number(fahrenheit) do
+ (fahrenheit - 32) * 5 / 9
+ end
+
+ @doc """
+ Converts Celsius to Fahrenheit
+ """
+ def c_to_f(celsius) when is_number(celsius) do
+ celsius * 9 / 5 + 32
+ end
+
+ @doc """
+ Converts mph to km/h
+ """
+ def mph_to_kph(mph) when is_number(mph) do
+ mph * 1.60934
+ end
+
+ @doc """
+ Converts km/h to mph
+ """
+ def kph_to_mph(kph) when is_number(kph) do
+ kph / 1.60934
+ end
+
+ @doc """
+ Converts inches to mm
+ """
+ def inches_to_mm(inches) when is_number(inches) do
+ inches * 25.4
+ end
+
+ @doc """
+ Converts mm to inches
+ """
+ def mm_to_inches(mm) when is_number(mm) do
+ mm / 25.4
+ end
end
diff --git a/lib/aprsme_web/live/map_live/callsign_view.ex b/lib/aprsme_web/live/map_live/callsign_view.ex
index 1dd5242..7f61989 100644
--- a/lib/aprsme_web/live/map_live/callsign_view.ex
+++ b/lib/aprsme_web/live/map_live/callsign_view.ex
@@ -329,7 +329,8 @@ defmodule AprsmeWeb.MapLive.CallsignView do
socket = assign(socket, visible_packets: updated_visible_packets)
# Live packets are always the most recent for their callsign
- packet_data = PacketUtils.build_packet_data(packet, true)
+ locale = Map.get(socket.assigns, :locale, "en")
+ packet_data = PacketUtils.build_packet_data(packet, true, locale)
socket =
if packet_data,
@@ -355,7 +356,9 @@ defmodule AprsmeWeb.MapLive.CallsignView do
end
defp handle_replay_packet(packet, socket) do
- case PacketUtils.build_packet_data(packet) do
+ locale = Map.get(socket.assigns, :locale, "en")
+
+ case PacketUtils.build_packet_data(packet, false, locale) do
nil -> handle_invalid_replay_packet(socket)
packet_data -> handle_valid_replay_packet(packet, packet_data, socket)
end
@@ -814,7 +817,8 @@ defmodule AprsmeWeb.MapLive.CallsignView do
end
defp build_single_historical_packet_data(packet, index, callsign) do
- case PacketUtils.build_packet_data(packet) do
+ # Note: We don't have access to locale here, so we'll use default "en"
+ case PacketUtils.build_packet_data(packet, false, "en") do
nil ->
nil
@@ -847,7 +851,8 @@ defmodule AprsmeWeb.MapLive.CallsignView do
defp push_latest_marker(socket, latest_packet) do
if latest_packet do
- packet_data = PacketUtils.build_packet_data(latest_packet, true)
+ locale = Map.get(socket.assigns, :locale, "en")
+ packet_data = PacketUtils.build_packet_data(latest_packet, true, locale)
if packet_data,
do: {push_event(socket, "new_packet", packet_data), true},
@@ -992,7 +997,8 @@ defmodule AprsmeWeb.MapLive.CallsignView do
if Map.get(socket.assigns, :latest_marker_pushed, false) do
socket
else
- packet_data = PacketUtils.build_packet_data(packet, true)
+ locale = Map.get(socket.assigns, :locale, "en")
+ packet_data = PacketUtils.build_packet_data(packet, true, locale)
if packet_data, do: push_event(socket, "new_packet", packet_data), else: socket
end
end
diff --git a/lib/aprsme_web/live/map_live/index.ex b/lib/aprsme_web/live/map_live/index.ex
index 0abbf77..a1279b1 100644
--- a/lib/aprsme_web/live/map_live/index.ex
+++ b/lib/aprsme_web/live/map_live/index.ex
@@ -144,9 +144,11 @@ defmodule AprsmeWeb.MapLive.Index do
end)
|> Map.new()
+ locale = Map.get(socket.assigns, :locale, "en")
+
visible_packets_list =
filtered_packets
- |> Enum.map(fn {_callsign, packet} -> PacketUtils.build_packet_data(packet) end)
+ |> Enum.map(fn {_callsign, packet} -> PacketUtils.build_packet_data(packet, false, locale) end)
|> Enum.filter(& &1)
socket = assign(socket, visible_packets: filtered_packets)
@@ -398,7 +400,8 @@ defmodule AprsmeWeb.MapLive.Index do
new_visible_packets = Map.put(socket.assigns.visible_packets, callsign_key, packet)
# Live packets are always the most recent for their callsign
- marker_data = PacketUtils.build_packet_data(packet, true)
+ locale = Map.get(socket.assigns, :locale, "en")
+ marker_data = PacketUtils.build_packet_data(packet, true, locale)
socket =
if marker_data do
@@ -1046,7 +1049,8 @@ defmodule AprsmeWeb.MapLive.Index do
# Only show as red dot if it's not the most recent position
is_most_recent = index == 0
- packet_data = PacketUtils.build_packet_data(packet, is_most_recent)
+ # Note: We don't have access to locale here, so we'll use default "en"
+ packet_data = PacketUtils.build_packet_data(packet, is_most_recent, "en")
if packet_data do
packet_data
diff --git a/lib/aprsme_web/live/map_live/packet_utils.ex b/lib/aprsme_web/live/map_live/packet_utils.ex
index 0684ec8..616407a 100644
--- a/lib/aprsme_web/live/map_live/packet_utils.ex
+++ b/lib/aprsme_web/live/map_live/packet_utils.ex
@@ -137,24 +137,25 @@ defmodule AprsmeWeb.MapLive.PacketUtils do
Map.get(data_extended, to_string(key)) || "N/A"
end
- def build_packet_data(packet, is_most_recent_for_callsign) when is_boolean(is_most_recent_for_callsign) do
+ def build_packet_data(packet, is_most_recent_for_callsign, locale \\ "en")
+ when is_boolean(is_most_recent_for_callsign) do
{lat, lon, data_extended} = MapHelpers.get_coordinates(packet)
callsign = generate_callsign(packet)
if lat && lon && callsign != "" && callsign != nil do
- packet_data = build_packet_map(packet, lat, lon, data_extended)
+ packet_data = build_packet_map(packet, lat, lon, data_extended, locale)
Map.put(packet_data, "is_most_recent_for_callsign", is_most_recent_for_callsign)
end
end
def build_packet_data(packet) do
- build_packet_data(packet, false)
+ build_packet_data(packet, false, "en")
end
- defp build_packet_map(packet, lat, lon, data_extended) do
+ defp build_packet_map(packet, lat, lon, data_extended, locale) do
data_extended = data_extended || %{}
packet_info = extract_packet_info(packet, data_extended)
- popup = build_popup_content(packet, packet_info, lat, lon)
+ popup = build_popup_content(packet, packet_info, lat, lon, locale)
build_packet_result(packet, packet_info, lat, lon, popup)
end
@@ -171,9 +172,9 @@ defmodule AprsmeWeb.MapLive.PacketUtils do
}
end
- defp build_popup_content(packet, packet_info, lat, lon) do
+ defp build_popup_content(packet, packet_info, lat, lon, locale) do
if packet_info.is_weather_packet do
- build_weather_popup_html(packet, packet_info.callsign)
+ build_weather_popup_html(packet, packet_info.callsign, locale)
else
build_standard_popup_html(packet_info, lat, lon)
end
@@ -197,11 +198,27 @@ defmodule AprsmeWeb.MapLive.PacketUtils do
|> IO.iodata_to_binary()
end
- defp build_weather_popup_html(packet, sender) do
+ defp build_weather_popup_html(packet, sender, locale) do
received_at = get_received_at(packet)
timestamp_dt = TimeHelpers.to_datetime(received_at)
cache_buster = System.system_time(:millisecond)
+ # Get weather data and convert units based on locale
+ temperature_raw = get_weather_field(packet, :temperature)
+ wind_speed_raw = get_weather_field(packet, :wind_speed)
+ wind_gust_raw = get_weather_field(packet, :wind_gust)
+ rain_1h_raw = get_weather_field(packet, :rain_1h)
+ rain_24h_raw = get_weather_field(packet, :rain_24h)
+ rain_since_midnight_raw = get_weather_field(packet, :rain_since_midnight)
+
+ # Convert units if the values are numbers
+ {temperature, temp_unit} = convert_temperature(temperature_raw, locale)
+ {wind_speed, wind_unit} = convert_wind_speed(wind_speed_raw, locale)
+ {wind_gust, gust_unit} = convert_wind_speed(wind_gust_raw, locale)
+ {rain_1h, rain_unit} = convert_rain(rain_1h_raw, locale)
+ {rain_24h, rain_unit} = convert_rain(rain_24h_raw, locale)
+ {rain_since_midnight, rain_unit} = convert_rain(rain_since_midnight_raw, locale)
+
%{
callsign: sender,
comment: nil,
@@ -209,15 +226,19 @@ defmodule AprsmeWeb.MapLive.PacketUtils do
cache_buster: cache_buster,
weather: true,
weather_link: true,
- temperature: get_weather_field(packet, :temperature),
+ temperature: temperature,
+ temp_unit: temp_unit,
humidity: get_weather_field(packet, :humidity),
wind_direction: get_weather_field(packet, :wind_direction),
- wind_speed: get_weather_field(packet, :wind_speed),
- wind_gust: get_weather_field(packet, :wind_gust),
+ wind_speed: wind_speed,
+ wind_unit: wind_unit,
+ wind_gust: wind_gust,
+ gust_unit: gust_unit,
pressure: get_weather_field(packet, :pressure),
- rain_1h: get_weather_field(packet, :rain_1h),
- rain_24h: get_weather_field(packet, :rain_24h),
- rain_since_midnight: get_weather_field(packet, :rain_since_midnight)
+ rain_1h: rain_1h,
+ rain_24h: rain_24h,
+ rain_since_midnight: rain_since_midnight,
+ rain_unit: rain_unit
}
|> PopupComponent.popup()
|> Safe.to_iodata()
@@ -259,4 +280,23 @@ defmodule AprsmeWeb.MapLive.PacketUtils do
true -> nil
end
end
+
+ # Weather unit conversion helpers
+ defp convert_temperature(value, locale) when is_number(value) do
+ AprsmeWeb.WeatherUnits.format_temperature(value, locale)
+ end
+
+ defp convert_temperature(value, _locale), do: {value, "°F"}
+
+ defp convert_wind_speed(value, locale) when is_number(value) do
+ AprsmeWeb.WeatherUnits.format_wind_speed(value, locale)
+ end
+
+ defp convert_wind_speed(value, _locale), do: {value, "mph"}
+
+ defp convert_rain(value, locale) when is_number(value) do
+ AprsmeWeb.WeatherUnits.format_rain(value, locale)
+ end
+
+ defp convert_rain(value, _locale), do: {value, "in"}
end
diff --git a/lib/aprsme_web/live/map_live/popup_component.ex b/lib/aprsme_web/live/map_live/popup_component.ex
index 863ae16..b2635d0 100644
--- a/lib/aprsme_web/live/map_live/popup_component.ex
+++ b/lib/aprsme_web/live/map_live/popup_component.ex
@@ -5,6 +5,8 @@ defmodule AprsmeWeb.MapLive.PopupComponent do
import AprsmeWeb.TimeHelpers
import Gettext
+ alias AprsmeWeb.WeatherUnits
+
def popup(assigns) do
~H"""
"""
diff --git a/lib/aprsme_web/live/weather_live/callsign_view.ex b/lib/aprsme_web/live/weather_live/callsign_view.ex
index 29c6d6f..3fc42e6 100644
--- a/lib/aprsme_web/live/weather_live/callsign_view.ex
+++ b/lib/aprsme_web/live/weather_live/callsign_view.ex
@@ -7,6 +7,7 @@ defmodule AprsmeWeb.WeatherLive.CallsignView do
alias Aprsme.Packets
alias AprsmeWeb.MapLive.PacketUtils
+ alias AprsmeWeb.WeatherUnits
@impl true
def mount(%{"callsign" => callsign}, _session, socket) do
@@ -22,6 +23,10 @@ defmodule AprsmeWeb.WeatherLive.CallsignView do
{start_time, end_time} = default_time_range()
weather_history = get_weather_history(normalized_callsign, start_time, end_time)
+ # Get locale from socket assigns (set by LocaleHook)
+ locale = Map.get(socket.assigns, :locale, "en")
+ unit_labels = WeatherUnits.unit_labels(locale)
+
weather_history_json =
weather_history
|> Enum.map(fn pkt ->
@@ -30,36 +35,44 @@ defmodule AprsmeWeb.WeatherLive.CallsignView do
calc_dew_point(pkt.temperature, pkt.humidity)
end
+ # Convert units based on locale
+ {temp_value, _} = WeatherUnits.format_temperature(pkt.temperature, locale)
+ {dew_value, _} = if dew_point, do: WeatherUnits.format_temperature(dew_point, locale), else: {nil, nil}
+ {wind_speed_value, _} = WeatherUnits.format_wind_speed(pkt.wind_speed, locale)
+ {rain_1h_value, _} = WeatherUnits.format_rain(pkt.rain_1h, locale)
+ {rain_24h_value, _} = WeatherUnits.format_rain(pkt.rain_24h, locale)
+ {rain_since_midnight_value, _} = WeatherUnits.format_rain(pkt.rain_since_midnight, locale)
+
%{
timestamp: pkt.received_at,
- temperature: pkt.temperature,
- dew_point: dew_point,
+ temperature: temp_value,
+ dew_point: dew_value,
humidity: pkt.humidity,
pressure: pkt.pressure,
wind_direction: pkt.wind_direction,
- wind_speed: pkt.wind_speed,
- rain_1h: pkt.rain_1h,
- rain_24h: pkt.rain_24h,
- rain_since_midnight: pkt.rain_since_midnight,
+ wind_speed: wind_speed_value,
+ rain_1h: rain_1h_value,
+ rain_24h: rain_24h_value,
+ rain_since_midnight: rain_since_midnight_value,
luminosity: pkt.luminosity
}
end)
|> Jason.encode!()
- # Add chart labels for translation
+ # Add chart labels for translation with locale-aware units
chart_labels = %{
- temp_title: gettext("Temperature & Dew Point (°F)"),
- temp_label: gettext("Temperature (°F)"),
- dew_label: gettext("Dew Point (°F)"),
+ temp_title: gettext("Temperature & Dew Point (%{unit})", unit: unit_labels.temperature),
+ temp_label: gettext("Temperature (%{unit})", unit: unit_labels.temperature),
+ dew_label: gettext("Dew Point (%{unit})", unit: unit_labels.temperature),
humidity_title: gettext("Humidity (%)"),
humidity_label: gettext("Humidity (%)"),
pressure_title: gettext("Pressure (mb)"),
pressure_label: gettext("Pressure (mb)"),
- wind_title: gettext("Wind (mph)"),
- wind_label: gettext("Wind Speed (mph)"),
- gust_label: gettext("Wind Gust (mph)"),
+ wind_title: gettext("Wind (%{unit})", unit: unit_labels.wind_speed),
+ wind_label: gettext("Wind Speed (%{unit})", unit: unit_labels.wind_speed),
+ gust_label: gettext("Wind Gust (%{unit})", unit: unit_labels.wind_speed),
time: gettext("Time"),
- degf: gettext("°F"),
+ degf: unit_labels.temperature,
percent: gettext("%"),
mb: gettext("mb")
}
@@ -83,6 +96,9 @@ defmodule AprsmeWeb.WeatherLive.CallsignView do
{start_time, end_time} = default_time_range()
weather_history = get_weather_history(socket.assigns.callsign, start_time, end_time)
+ # Get locale from socket assigns
+ locale = Map.get(socket.assigns, :locale, "en")
+
weather_history_json =
weather_history
|> Enum.map(fn pkt ->
@@ -91,17 +107,25 @@ defmodule AprsmeWeb.WeatherLive.CallsignView do
calc_dew_point(pkt.temperature, pkt.humidity)
end
+ # Convert units based on locale
+ {temp_value, _} = WeatherUnits.format_temperature(pkt.temperature, locale)
+ {dew_value, _} = if dew_point, do: WeatherUnits.format_temperature(dew_point, locale), else: {nil, nil}
+ {wind_speed_value, _} = WeatherUnits.format_wind_speed(pkt.wind_speed, locale)
+ {rain_1h_value, _} = WeatherUnits.format_rain(pkt.rain_1h, locale)
+ {rain_24h_value, _} = WeatherUnits.format_rain(pkt.rain_24h, locale)
+ {rain_since_midnight_value, _} = WeatherUnits.format_rain(pkt.rain_since_midnight, locale)
+
%{
timestamp: pkt.received_at,
- temperature: pkt.temperature,
- dew_point: dew_point,
+ temperature: temp_value,
+ dew_point: dew_value,
humidity: pkt.humidity,
pressure: pkt.pressure,
wind_direction: pkt.wind_direction,
- wind_speed: pkt.wind_speed,
- rain_1h: pkt.rain_1h,
- rain_24h: pkt.rain_24h,
- rain_since_midnight: pkt.rain_since_midnight,
+ wind_speed: wind_speed_value,
+ rain_1h: rain_1h_value,
+ rain_24h: rain_24h_value,
+ rain_since_midnight: rain_since_midnight_value,
luminosity: pkt.luminosity
}
end)
@@ -128,6 +152,9 @@ defmodule AprsmeWeb.WeatherLive.CallsignView do
{start_time, end_time} = default_time_range()
weather_history = get_weather_history(socket.assigns.callsign, start_time, end_time)
+ # Get locale from socket assigns
+ locale = Map.get(socket.assigns, :locale, "en")
+
weather_history_json =
weather_history
|> Enum.map(fn pkt ->
@@ -136,17 +163,25 @@ defmodule AprsmeWeb.WeatherLive.CallsignView do
calc_dew_point(pkt.temperature, pkt.humidity)
end
+ # Convert units based on locale
+ {temp_value, _} = WeatherUnits.format_temperature(pkt.temperature, locale)
+ {dew_value, _} = if dew_point, do: WeatherUnits.format_temperature(dew_point, locale), else: {nil, nil}
+ {wind_speed_value, _} = WeatherUnits.format_wind_speed(pkt.wind_speed, locale)
+ {rain_1h_value, _} = WeatherUnits.format_rain(pkt.rain_1h, locale)
+ {rain_24h_value, _} = WeatherUnits.format_rain(pkt.rain_24h, locale)
+ {rain_since_midnight_value, _} = WeatherUnits.format_rain(pkt.rain_since_midnight, locale)
+
%{
timestamp: pkt.received_at,
- temperature: pkt.temperature,
- dew_point: dew_point,
+ temperature: temp_value,
+ dew_point: dew_value,
humidity: pkt.humidity,
pressure: pkt.pressure,
wind_direction: pkt.wind_direction,
- wind_speed: pkt.wind_speed,
- rain_1h: pkt.rain_1h,
- rain_24h: pkt.rain_24h,
- rain_since_midnight: pkt.rain_since_midnight,
+ wind_speed: wind_speed_value,
+ rain_1h: rain_1h_value,
+ rain_24h: rain_24h_value,
+ rain_since_midnight: rain_since_midnight_value,
luminosity: pkt.luminosity
}
end)
@@ -220,4 +255,44 @@ defmodule AprsmeWeb.WeatherLive.CallsignView do
_ -> value
end
end
+
+ @doc """
+ Formats weather values with appropriate units based on locale.
+ """
+ def format_weather_value(packet, key, locale) do
+ value = PacketUtils.get_weather_field(packet, key)
+
+ case {key, value} do
+ {:temperature, value} when is_number(value) ->
+ {converted_value, unit} = WeatherUnits.format_temperature(value, locale)
+ "#{converted_value}#{unit}"
+
+ {:wind_speed, value} when is_number(value) ->
+ {converted_value, unit} = WeatherUnits.format_wind_speed(value, locale)
+ "#{converted_value} #{unit}"
+
+ {:wind_gust, value} when is_number(value) ->
+ {converted_value, unit} = WeatherUnits.format_wind_speed(value, locale)
+ "#{converted_value} #{unit}"
+
+ {:rain_1h, value} when is_number(value) ->
+ {converted_value, unit} = WeatherUnits.format_rain(value, locale)
+ "#{converted_value} #{unit}"
+
+ {:rain_24h, value} when is_number(value) ->
+ {converted_value, unit} = WeatherUnits.format_rain(value, locale)
+ "#{converted_value} #{unit}"
+
+ {:rain_since_midnight, value} when is_number(value) ->
+ {converted_value, unit} = WeatherUnits.format_rain(value, locale)
+ "#{converted_value} #{unit}"
+
+ _ ->
+ case value do
+ "N/A" -> "N/A"
+ nil -> "N/A"
+ _ -> "#{value}"
+ end
+ end
+ end
end
diff --git a/lib/aprsme_web/live/weather_live/callsign_view.html.heex b/lib/aprsme_web/live/weather_live/callsign_view.html.heex
index b130702..2dc5b57 100644
--- a/lib/aprsme_web/live/weather_live/callsign_view.html.heex
+++ b/lib/aprsme_web/live/weather_live/callsign_view.html.heex
@@ -96,7 +96,7 @@
{gettext("Temperature")}
- {PacketUtils.get_weather_field(@weather_packet, :temperature)}°F
+ {format_weather_value(@weather_packet, :temperature, @locale)}
@@ -108,16 +108,17 @@
{gettext("Wind")}
- {PacketUtils.get_weather_field(@weather_packet, :wind_direction)}° @ {PacketUtils.get_weather_field(
+ {PacketUtils.get_weather_field(@weather_packet, :wind_direction)}° @ {format_weather_value(
@weather_packet,
- :wind_speed
- )} mph
+ :wind_speed,
+ @locale
+ )}
{gettext("Gusts")}
- {PacketUtils.get_weather_field(@weather_packet, :wind_gust)} mph
+ {format_weather_value(@weather_packet, :wind_gust, @locale)}
@@ -129,19 +130,19 @@
{gettext("Rain (1h)")}
- {get_weather_field_zero(@weather_packet, :rain_1h)} in
+ {format_weather_value(@weather_packet, :rain_1h, @locale)}
{gettext("Rain (24h)")}
- {get_weather_field_zero(@weather_packet, :rain_24h)} in
+ {format_weather_value(@weather_packet, :rain_24h, @locale)}
{gettext("Rain (since midnight)")}
- {get_weather_field_zero(@weather_packet, :rain_since_midnight)} in
+ {format_weather_value(@weather_packet, :rain_since_midnight, @locale)}
diff --git a/lib/aprsme_web/weather_units.ex b/lib/aprsme_web/weather_units.ex
new file mode 100644
index 0000000..86173cd
--- /dev/null
+++ b/lib/aprsme_web/weather_units.ex
@@ -0,0 +1,98 @@
+defmodule AprsmeWeb.WeatherUnits do
+ @moduledoc """
+ Handles weather unit conversions and formatting based on locale.
+ Supports imperial (US) and metric (international) units.
+ """
+
+ alias Aprsme.Convert
+
+ @doc """
+ Determines the unit system based on locale.
+ Returns :imperial for US, :metric for most other countries.
+ """
+ def unit_system(locale) when is_binary(locale) do
+ case locale do
+ # Default to imperial for English
+ "en" -> :imperial
+ # Spanish-speaking countries mostly use metric
+ "es" -> :metric
+ # Germany uses metric
+ "de" -> :metric
+ # France uses metric
+ "fr" -> :metric
+ # Default to metric for unknown locales
+ _ -> :metric
+ end
+ end
+
+ @doc """
+ Converts temperature from Fahrenheit to Celsius if needed.
+ Returns the temperature in the appropriate unit for the locale.
+ """
+ def format_temperature(temp, locale) when is_number(temp) do
+ case unit_system(locale) do
+ :imperial -> {temp, "°F"}
+ :metric -> {Convert.f_to_c(temp), "°C"}
+ end
+ end
+
+ def format_temperature(temp, _locale), do: {temp, "°F"}
+
+ @doc """
+ Converts wind speed from mph to km/h if needed.
+ Returns the wind speed in the appropriate unit for the locale.
+ """
+ def format_wind_speed(speed, locale) when is_number(speed) do
+ case unit_system(locale) do
+ :imperial -> {speed, "mph"}
+ :metric -> {Convert.mph_to_kph(speed), "km/h"}
+ end
+ end
+
+ def format_wind_speed(speed, _locale), do: {speed, "mph"}
+
+ @doc """
+ Converts rain from inches to mm if needed.
+ Returns the rain amount in the appropriate unit for the locale.
+ """
+ def format_rain(rain, locale) when is_number(rain) do
+ case unit_system(locale) do
+ :imperial -> {rain, "in"}
+ :metric -> {Convert.inches_to_mm(rain), "mm"}
+ end
+ end
+
+ def format_rain(rain, _locale), do: {rain, "in"}
+
+ @doc """
+ Formats pressure (keeps hPa for all locales as it's standard).
+ """
+ def format_pressure(pressure, _locale) when is_number(pressure) do
+ {pressure, "hPa"}
+ end
+
+ def format_pressure(pressure, _locale), do: {pressure, "hPa"}
+
+ @doc """
+ Gets the appropriate unit labels for the locale.
+ """
+ def unit_labels(locale) do
+ case unit_system(locale) do
+ :imperial ->
+ %{
+ temperature: "°F",
+ wind_speed: "mph",
+ rain: "in",
+ pressure: "hPa"
+ }
+
+ :metric ->
+ %{
+ temperature: "°C",
+ wind_speed: "km/h",
+ rain: "mm",
+ pressure: "hPa"
+ }
+ end
+ end
+end