preskok
uilocale-contextsource: ok · refreshed
Locale Context
Locale context provider for internationalization support
npx shadcn add "https://ui-three-mu.vercel.app/r/locale-context.json"free
No selection tags yet — empty means no evidence, not lack of support.
Dependencies
Bundle weight · lightreact-number-format
Registry dependencies
https://ui-three-mu.vercel.app/r/create-ctx.json
Files3 · source cached 10/8/2026, 6:48:13 AM
registry/preskok/ui/preskok-ui/locale-context/locale-context.tsx
"use client"
import type { PropsWithChildren } from "react"
import React, { useState } from "react"
import { createCtx } from "@/lib/create-ctx"
import { getCurrencyCodeOrSymbol } from "../number-format/currency-helpers"
import { DEFAULT_LOCALE, Locale } from "./locale-helpers"
const splitCurrentUrl = () => {
return {
origin: window.location.origin,
hostname: window.location.hostname,
pathname: window.location.pathname,
search: window.location.search,
hash: window.location.hash,
}
}
const retrieveLocaleFromUrlStrict = (passedUrl?: string): Locale | null => {
const url = passedUrl || splitCurrentUrl().pathname
const availableLocalesArray: Array<Locale> = Object.values(Locale)
const supposedUrlLocale = url.split("/")[1] as Locale | undefined
return supposedUrlLocale && availableLocalesArray.includes(supposedUrlLocale)
? supposedUrlLocale
: null
}
type CurrencyCodeOrSymbolExpectedOutputOptions =
| "currency_code"
| "currency_symbol"
interface GetCurrencyCodeOrSymbolParams {
inputValue: string
expectedOutput?: CurrencyCodeOrSymbolExpectedOutputOptions
}
interface LocaleContextProviderProps {
globalLocale: Locale
setGlobalLocale: (localeOption: Locale) => void
}
export const [useLocaleContext, LocaleContextProvider] =
createCtx<LocaleContextProviderProps>()
export const LocaleContext: React.FC<PropsWithChildren> = ({ children }) => {
const [locale, setLocale] = useState<Locale>(() => {
if (typeof window === "undefined") {
return DEFAULT_LOCALE
}
return retrieveLocaleFromUrlStrict() ?? DEFAULT_LOCALE
})
const setGlobalLocale = (localeOption: Locale): void => {
setLocale(localeOption)
}
/**
* This function will return the currency code or symbol code based on the input value and the expected output.
*
* IMPORTANT: It currently does not take into the account the locale value due to the fact we have a problem in business
* logic and we are using the '/en/' or '/sl/' in the URL to reflect the locale which is incorrect. We should be using the
* BCP47 standard which would equate to '/en-US/' or '/en-EN/' or '/en-GB/' or '/sl-SI/'.
*/
const getCurrencyCodeOrSymbolCode = ({
inputValue,
expectedOutput = "currency_code",
}: GetCurrencyCodeOrSymbolParams) => {
return getCurrencyCodeOrSymbol({ inputValue, expectedOutput })
}
const memoizedContextProps = {
globalLocale: locale,
setGlobalLocale,
getCurrencyCodeOrSymbolCode: getCurrencyCodeOrSymbolCode,
}
return (
<LocaleContextProvider value={memoizedContextProps}>
{children}
</LocaleContextProvider>
)
}
registry/preskok/ui/preskok-ui/locale-context/locale-helpers.ts
import type { NumericFormatProps } from "react-number-format"
export const Locale = {
DE: "de",
EN: "en",
FR: "fr",
IT: "it",
HR: "hr",
SL: "sl",
} as const
export type Locale = (typeof Locale)[keyof typeof Locale]
export const LocaleToBcp47Map = {
de: "de-DE",
en: "en-EN",
fr: "fr-FR",
it: "it-IT",
hr: "hr-HR",
sl: "sl-SL",
} as const
export type LocaleToBcp47Map =
(typeof LocaleToBcp47Map)[keyof typeof LocaleToBcp47Map]
export const CurrencyCodeAndSymbolMap = {
USD: "$",
EUR: "€",
GBP: "£",
} as const
export type CurrencyCodeAndSymbolMap =
(typeof CurrencyCodeAndSymbolMap)[keyof typeof CurrencyCodeAndSymbolMap]
export const Bcp47CountryLanguageCodeToCurrencyCodeMap = {
"en-US": "USD",
"en-GB": "GBP",
"en-EN": "EUR",
"de-DE": "EUR",
"de-AT": "EUR",
"de-CH": "EUR",
"el-GR": "EUR",
"en-IE": "EUR",
"fr-FR": "EUR",
"it-IT": "EUR",
"es-ES": "EUR",
"pt-PT": "EUR",
"sk-SK": "EUR",
"sv-SE": "EUR",
"da-DK": "EUR",
"fi-FI": "EUR",
"cs-CZ": "EUR",
"it-CH": "EUR",
"nl-NL": "EUR",
"hu-HU": "EUR",
"fr-BE": "EUR",
"nl-BE": "EUR",
} as const
export type Bcp47CountryLanguageCodeToCurrencyCodeMap =
(typeof Bcp47CountryLanguageCodeToCurrencyCodeMap)[keyof typeof Bcp47CountryLanguageCodeToCurrencyCodeMap]
export const DEFAULT_LOCALE = Locale.SL
export const DEFAULT_NUMBER_OF_DECIMALS = 2
export const DEFAULT_INVALID_NUMBER_TEXT = "Invalid number"
export const MAXIMUM_NUMBER_OF_DIGITS_ALLOWED = 12
export const LOCALE_TO_BCP_47_MAP: Record<Locale, LocaleToBcp47Map> = {
de: "de-DE",
en: "en-EN",
fr: "fr-FR",
it: "it-IT",
hr: "hr-HR",
sl: "sl-SL",
}
export const DEFAULT_NUMERIC_FORMAT_OPTIONS: NumericFormatProps = {
displayType: "text",
thousandSeparator: ".",
decimalSeparator: ",",
allowNegative: true,
decimalScale: DEFAULT_NUMBER_OF_DECIMALS,
}
export const SLOVENE_NUMERIC_FORMAT_OPTIONS: NumericFormatProps = {
...DEFAULT_NUMERIC_FORMAT_OPTIONS,
thousandSeparator: ".",
decimalSeparator: ",",
}
export const GERMAN_NUMERIC_FORMAT_OPTIONS: NumericFormatProps = {
...SLOVENE_NUMERIC_FORMAT_OPTIONS,
}
export const ITALIAN_NUMERIC_FORMAT_OPTIONS: NumericFormatProps = {
...SLOVENE_NUMERIC_FORMAT_OPTIONS,
}
export const CROATIAN_NUMERIC_FORMAT_OPTIONS: NumericFormatProps = {
...SLOVENE_NUMERIC_FORMAT_OPTIONS,
}
export const FRENCH_NUMERIC_FORMAT_OPTIONS: NumericFormatProps = {
...DEFAULT_NUMERIC_FORMAT_OPTIONS,
thousandSeparator: " ",
decimalSeparator: ",",
}
export const ENGLISH_NUMERIC_FORMAT_OPTIONS: NumericFormatProps = {
...DEFAULT_NUMERIC_FORMAT_OPTIONS,
thousandSeparator: ",",
decimalSeparator: ".",
}
export const LOCALE_TO_NUMERIC_FORMAT_OPTIONS_MAP: Record<
Locale,
NumericFormatProps
> = {
de: GERMAN_NUMERIC_FORMAT_OPTIONS,
en: ENGLISH_NUMERIC_FORMAT_OPTIONS,
fr: FRENCH_NUMERIC_FORMAT_OPTIONS,
it: ITALIAN_NUMERIC_FORMAT_OPTIONS,
hr: CROATIAN_NUMERIC_FORMAT_OPTIONS,
sl: SLOVENE_NUMERIC_FORMAT_OPTIONS,
}
registry/preskok/ui/preskok-ui/number-format/currency-helpers.ts
import { CurrencyCodeAndSymbolMap } from "../locale-context/locale-helpers"
type CurrencyCodeOrSymbolExpectedOutputOptions =
| "currency_code"
| "currency_symbol"
interface GetCurrencyCodeOrSymbolParams {
inputValue: string
expectedOutput?: CurrencyCodeOrSymbolExpectedOutputOptions
}
/**
* getCurrencyCodeOrSymbol is a helper function to get currency code or symbol from a string value. If no match is found
* we return an empty string.
*
* @param {string} inputValue -> string value that might be a currency code or symbol.
* @param {'currency_code' | 'currency_symbol'} expectedOutput -> optional expected output type (default: 'currency_code').
* @returns {string} - currency code or symbol or an empty string if no match is found
*/
export const getCurrencyCodeOrSymbol = ({
inputValue,
expectedOutput = "currency_code",
}: GetCurrencyCodeOrSymbolParams): string => {
let currencyCodeOrSymbolStringValue = ""
const trimmedAndLowerCaseInput = inputValue.trim().toLowerCase()
const currencyCodeOrSymbolLookup = Object.keys(CurrencyCodeAndSymbolMap).find(
(key) =>
key.toLowerCase() === trimmedAndLowerCaseInput ||
CurrencyCodeAndSymbolMap[
key as keyof typeof CurrencyCodeAndSymbolMap
].toLowerCase() === trimmedAndLowerCaseInput
)
if (currencyCodeOrSymbolLookup) {
if (expectedOutput === "currency_code") {
currencyCodeOrSymbolStringValue = currencyCodeOrSymbolLookup
} else {
currencyCodeOrSymbolStringValue =
CurrencyCodeAndSymbolMap[
currencyCodeOrSymbolLookup as keyof typeof CurrencyCodeAndSymbolMap
]
}
}
return currencyCodeOrSymbolStringValue
}