diff --git a/src/features/time/Clock.jsx b/src/features/time/Clock.jsx
index 99a40bea..f334aeb1 100644
--- a/src/features/time/Clock.jsx
+++ b/src/features/time/Clock.jsx
@@ -1,7 +1,7 @@
import { useState, useEffect, useRef } from 'react';
import { convertTimezone } from 'utils/date';
-import { formatPercentage } from 'utils/formatNumber';
+import { formatPercentage, formatDigits } from 'utils/formatNumber';
import { AnalogClock } from './components/AnalogClock';
import { VerticalClock } from './components/VerticalClock';
import EventBus from 'utils/eventbus';
@@ -50,21 +50,24 @@ const Clock = () => {
const zero = localStorage.getItem('zero');
if (localStorage.getItem('seconds') === 'true') {
- sec = `:${('00' + now.getSeconds()).slice(-2)}`;
- setFinalSeconds(`${('00' + now.getSeconds()).slice(-2)}`);
+ const secs = ('00' + now.getSeconds()).slice(-2);
+ sec = `:${formatDigits(secs)}`;
+ setFinalSeconds(formatDigits(secs));
}
if (localStorage.getItem('timeformat') === 'twentyfourhour') {
if (zero === 'false') {
- time = `${now.getHours()}:${('00' + now.getMinutes()).slice(-2)}:${sec}`;
- setFinalHour(`${now.getHours()}`);
- setFinalMinute(`${('00' + now.getMinutes()).slice(-2)}`);
+ const hours = now.getHours();
+ const minutes = ('00' + now.getMinutes()).slice(-2);
+ time = `${formatDigits(hours)}:${formatDigits(minutes)}${sec}`;
+ setFinalHour(formatDigits(hours));
+ setFinalMinute(formatDigits(minutes));
} else {
- time = `${('00' + now.getHours()).slice(-2)}:${('00' + now.getMinutes()).slice(
- -2,
- )}${sec}`;
- setFinalHour(`${('00' + now.getHours()).slice(-2)}`);
- setFinalMinute(`${('00' + now.getMinutes()).slice(-2)}`);
+ const hours = ('00' + now.getHours()).slice(-2);
+ const minutes = ('00' + now.getMinutes()).slice(-2);
+ time = `${formatDigits(hours)}:${formatDigits(minutes)}${sec}`;
+ setFinalHour(formatDigits(hours));
+ setFinalMinute(formatDigits(minutes));
}
setTime(time);
@@ -80,13 +83,16 @@ const Clock = () => {
}
if (zero === 'false') {
- time = `${hours}:${('00' + now.getMinutes()).slice(-2)}${sec}`;
- setFinalHour(`${hours}`);
- setFinalMinute(`${('00' + now.getMinutes()).slice(-2)}`);
+ const minutes = ('00' + now.getMinutes()).slice(-2);
+ time = `${formatDigits(hours)}:${formatDigits(minutes)}${sec}`;
+ setFinalHour(formatDigits(hours));
+ setFinalMinute(formatDigits(minutes));
} else {
- time = `${('00' + hours).slice(-2)}:${('00' + now.getMinutes()).slice(-2)}${sec}`;
- setFinalHour(`${('00' + hours).slice(-2)}`);
- setFinalMinute(`${('00' + now.getMinutes()).slice(-2)}`);
+ const paddedHours = ('00' + hours).slice(-2);
+ const minutes = ('00' + now.getMinutes()).slice(-2);
+ time = `${formatDigits(paddedHours)}:${formatDigits(minutes)}${sec}`;
+ setFinalHour(formatDigits(paddedHours));
+ setFinalMinute(formatDigits(minutes));
}
setTime(time);
@@ -137,11 +143,7 @@ const Clock = () => {
if (localStorage.getItem('timeType') === 'verticalClock') {
return (
-
+
);
}
diff --git a/src/features/weather/Weather.jsx b/src/features/weather/Weather.jsx
index 8f0dfa62..e1515ba2 100644
--- a/src/features/weather/Weather.jsx
+++ b/src/features/weather/Weather.jsx
@@ -1,5 +1,6 @@
import variables from 'config/variables';
import { memo, useState, useEffect, useCallback } from 'react';
+import { formatNumber } from 'utils/formatNumber';
import WeatherIcon from './components/WeatherIcon';
import Expanded from './components/Expanded';
@@ -70,12 +71,12 @@ const WeatherWidget = memo(() => {
- {`${weatherData.weather.temp}${weatherData.temp_text}`}
+ {`${formatNumber(weatherData.weather.temp)}${weatherData.temp_text}`}
{weatherType >= 2 && (
- {`${weatherData.weather.temp_min}${weatherData.temp_text}`}
- {`${weatherData.weather.temp_max}${weatherData.temp_text}`}
+ {`${formatNumber(weatherData.weather.temp_min)}${weatherData.temp_text}`}
+ {`${formatNumber(weatherData.weather.temp_max)}${weatherData.temp_text}`}
)}
@@ -83,7 +84,7 @@ const WeatherWidget = memo(() => {
{variables.getMessage('widgets.weather.feels_like', {
- amount: `${weatherData.weather.feels_like}${weatherData.temp_text}`,
+ amount: `${formatNumber(weatherData.weather.feels_like)}${weatherData.temp_text}`,
})}
{location}
diff --git a/src/features/weather/api/getWeather.js b/src/features/weather/api/getWeather.js
index ae0e67c8..86650948 100644
--- a/src/features/weather/api/getWeather.js
+++ b/src/features/weather/api/getWeather.js
@@ -9,6 +9,35 @@ const convertTemperature = (temp, format) => {
return Math.round(temp);
};
+const getLocalizedTempSymbol = (format) => {
+ const language = localStorage.getItem('language') || 'en_GB';
+ const baseLang = language.split('_')[0];
+
+ // Temperature symbols for different languages
+ const localizedSymbols = {
+ ar: {
+ celsius: '°س', // Arabic: Celsius (سيلزيوس)
+ fahrenheit: '°ف', // Arabic: Fahrenheit (فهرنهايت)
+ kelvin: 'ك', // Arabic: Kelvin (كلفن)
+ },
+ fa: {
+ celsius: '°س', // Persian: Celsius
+ fahrenheit: '°ف', // Persian: Fahrenheit
+ kelvin: 'ک', // Persian: Kelvin
+ },
+ };
+
+ // Default Western symbols
+ const defaultSymbols = {
+ celsius: '°C',
+ fahrenheit: '°F',
+ kelvin: 'K',
+ };
+
+ // Return localized symbol if available, otherwise default
+ return localizedSymbols[baseLang]?.[format] || defaultSymbols[format] || 'K';
+};
+
export const getWeather = async (location) => {
let cached = localStorage.getItem('currentWeather');
if (cached) {
@@ -40,15 +69,9 @@ export const getWeather = async (location) => {
const { temp, temp_min, temp_max, feels_like } = data.main;
const tempFormat = localStorage.getItem('tempformat');
- const tempSymbols = {
- celsius: '°C',
- kelvin: 'K',
- fahrenheit: '°F',
- };
-
const cacheable = {
icon: data.weather[0].icon,
- temp_text: tempSymbols[tempFormat] || 'K',
+ temp_text: getLocalizedTempSymbol(tempFormat),
weather: {
temp: convertTemperature(temp, tempFormat),
description: data.weather[0].description,
diff --git a/src/utils/data/default_settings.json b/src/utils/data/default_settings.json
index becaf659..e02ffb1f 100644
--- a/src/utils/data/default_settings.json
+++ b/src/utils/data/default_settings.json
@@ -237,7 +237,7 @@
},
{
"name": "localeFormatting",
- "value": false
+ "value": true
},
{
"name": "offlineMode",
diff --git a/src/utils/formatNumber.js b/src/utils/formatNumber.js
index 1312ed5c..22c3e262 100644
--- a/src/utils/formatNumber.js
+++ b/src/utils/formatNumber.js
@@ -1,8 +1,30 @@
/**
* Convert language code from Mue format (en_US) to locale format (en-US)
+ * and add numbering system extensions for languages that use non-Latin numerals
*/
export function getLocaleCode() {
- return localStorage.getItem('language')?.replace(/_/g, '-') || 'en-GB';
+ const language = localStorage.getItem('language')?.replace(/_/g, '-') || 'en-GB';
+
+ // Map language codes to their native numbering systems
+ const numberingSystems = {
+ ar: 'arab', // Arabic - Eastern Arabic numerals (٠-٩)
+ fa: 'arabext', // Persian - Extended Arabic-Indic numerals (۰-۹)
+ bn: 'beng', // Bengali - Bengali numerals (০-৯)
+ hi: 'deva', // Hindi - Devanagari numerals (०-९)
+ mr: 'deva', // Marathi - Devanagari numerals
+ ne: 'deva', // Nepali - Devanagari numerals
+ ta: 'tamldec', // Tamil - Tamil numerals (௦-௯)
+ };
+
+ // Get the base language code (e.g., 'ar' from 'ar-EG')
+ const baseLang = language.split('-')[0];
+
+ // If this language has a native numbering system, append it
+ if (numberingSystems[baseLang]) {
+ return `${language}-u-nu-${numberingSystems[baseLang]}`;
+ }
+
+ return language;
}
/**
@@ -12,7 +34,8 @@ export function getLocaleCode() {
* @returns {string} Formatted number string
*/
export function formatNumber(value, options = {}) {
- if (localStorage.getItem('localeFormatting') !== 'true') {
+ const localeFormatting = localStorage.getItem('localeFormatting');
+ if (localeFormatting === 'false' || localeFormatting === null) {
return String(value);
}
try {
@@ -28,7 +51,8 @@ export function formatNumber(value, options = {}) {
* @returns {string} Formatted percentage string
*/
export function formatPercentage(value) {
- if (localStorage.getItem('localeFormatting') !== 'true') {
+ const localeFormatting = localStorage.getItem('localeFormatting');
+ if (localeFormatting === 'false') {
return Math.round(value * 100) + '%';
}
try {
@@ -40,3 +64,24 @@ export function formatPercentage(value) {
return Math.round(value * 100) + '%';
}
}
+
+/**
+ * Format digits with locale-specific numerals (e.g., Eastern Arabic numerals for Arabic)
+ * @param {string|number} value - The value to format (e.g., '10', 23)
+ * @returns {string} Formatted string with locale-specific numerals
+ */
+export function formatDigits(value) {
+ const localeFormatting = localStorage.getItem('localeFormatting');
+ if (localeFormatting === 'false') {
+ return String(value);
+ }
+ try {
+ const numValue = typeof value === 'string' ? parseInt(value, 10) : value;
+ if (isNaN(numValue)) return String(value);
+ return new Intl.NumberFormat(getLocaleCode(), {
+ useGrouping: false,
+ }).format(numValue);
+ } catch {
+ return String(value);
+ }
+}