mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-09-22 15:32:48 +00:00
Fix(UI) : Added browser language support (#22132)
* support browser language * moved map to utils * fixed sidebar not rendering and unit tests * fixed localization rendering --------- Co-authored-by: Chirag Madlani <12962843+chirag-madlani@users.noreply.github.com>
This commit is contained in:
parent
e8bd7ea8a0
commit
85da793e6f
@ -17,10 +17,12 @@ import { useCallback, useEffect } from 'react';
|
|||||||
import { useLimitStore } from '../../context/LimitsProvider/useLimitsStore';
|
import { useLimitStore } from '../../context/LimitsProvider/useLimitsStore';
|
||||||
import { LineageSettings } from '../../generated/configuration/lineageSettings';
|
import { LineageSettings } from '../../generated/configuration/lineageSettings';
|
||||||
import { SettingType } from '../../generated/settings/settings';
|
import { SettingType } from '../../generated/settings/settings';
|
||||||
|
import { useCurrentUserPreferences } from '../../hooks/currentUserStore/useCurrentUserStore';
|
||||||
import { useApplicationStore } from '../../hooks/useApplicationStore';
|
import { useApplicationStore } from '../../hooks/useApplicationStore';
|
||||||
import { getLimitConfig } from '../../rest/limitsAPI';
|
import { getLimitConfig } from '../../rest/limitsAPI';
|
||||||
import { getSettingsByType } from '../../rest/settingConfigAPI';
|
import { getSettingsByType } from '../../rest/settingConfigAPI';
|
||||||
import applicationRoutesClass from '../../utils/ApplicationRoutesClassBase';
|
import applicationRoutesClass from '../../utils/ApplicationRoutesClassBase';
|
||||||
|
import i18n from '../../utils/i18next/LocalUtil';
|
||||||
import { LimitBanner } from '../common/LimitBanner/LimitBanner';
|
import { LimitBanner } from '../common/LimitBanner/LimitBanner';
|
||||||
import LeftSidebar from '../MyData/LeftSidebar/LeftSidebar.component';
|
import LeftSidebar from '../MyData/LeftSidebar/LeftSidebar.component';
|
||||||
import NavBar from '../NavBar/NavBar';
|
import NavBar from '../NavBar/NavBar';
|
||||||
@ -32,6 +34,9 @@ const { Content } = Layout;
|
|||||||
const AppContainer = () => {
|
const AppContainer = () => {
|
||||||
const { currentUser, setAppPreferences, appPreferences } =
|
const { currentUser, setAppPreferences, appPreferences } =
|
||||||
useApplicationStore();
|
useApplicationStore();
|
||||||
|
const {
|
||||||
|
preferences: { language },
|
||||||
|
} = useCurrentUserPreferences();
|
||||||
const AuthenticatedRouter = applicationRoutesClass.getRouteElements();
|
const AuthenticatedRouter = applicationRoutesClass.getRouteElements();
|
||||||
const ApplicationExtras = applicationsClassBase.getApplicationExtension();
|
const ApplicationExtras = applicationsClassBase.getApplicationExtension();
|
||||||
const { isAuthenticated } = useApplicationStore();
|
const { isAuthenticated } = useApplicationStore();
|
||||||
@ -61,6 +66,12 @@ const AppContainer = () => {
|
|||||||
}
|
}
|
||||||
}, [currentUser?.id]);
|
}, [currentUser?.id]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (language) {
|
||||||
|
i18n.changeLanguage(language);
|
||||||
|
}
|
||||||
|
}, [language]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
<LimitBanner />
|
<LimitBanner />
|
||||||
|
@ -27,7 +27,7 @@ const LeftSidebarItem = ({
|
|||||||
to={{
|
to={{
|
||||||
pathname: redirect_url,
|
pathname: redirect_url,
|
||||||
}}>
|
}}>
|
||||||
{title}
|
{t(title)}
|
||||||
|
|
||||||
{isBeta && (
|
{isBeta && (
|
||||||
<Badge
|
<Badge
|
||||||
@ -42,7 +42,7 @@ const LeftSidebarItem = ({
|
|||||||
<span
|
<span
|
||||||
className="left-panel-item left-panel-label p-0"
|
className="left-panel-item left-panel-label p-0"
|
||||||
data-testid={dataTestId}>
|
data-testid={dataTestId}>
|
||||||
{title}
|
{t(title)}
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -75,10 +75,8 @@ import {
|
|||||||
getEntityType,
|
getEntityType,
|
||||||
prepareFeedLink,
|
prepareFeedLink,
|
||||||
} from '../../utils/FeedUtils';
|
} from '../../utils/FeedUtils';
|
||||||
import {
|
import { languageSelectOptions } from '../../utils/i18next/i18nextUtil';
|
||||||
languageSelectOptions,
|
import { SupportedLocales } from '../../utils/i18next/LocalUtil.interface';
|
||||||
SupportedLocales,
|
|
||||||
} from '../../utils/i18next/i18nextUtil';
|
|
||||||
import { isCommandKeyPress, Keys } from '../../utils/KeyboardUtil';
|
import { isCommandKeyPress, Keys } from '../../utils/KeyboardUtil';
|
||||||
import { getHelpDropdownItems } from '../../utils/NavbarUtils';
|
import { getHelpDropdownItems } from '../../utils/NavbarUtils';
|
||||||
import { getSettingPath } from '../../utils/RouterUtils';
|
import { getSettingPath } from '../../utils/RouterUtils';
|
||||||
@ -118,7 +116,7 @@ const NavBar = () => {
|
|||||||
const [version, setVersion] = useState<string>();
|
const [version, setVersion] = useState<string>();
|
||||||
const [isDomainDropdownOpen, setIsDomainDropdownOpen] = useState(false);
|
const [isDomainDropdownOpen, setIsDomainDropdownOpen] = useState(false);
|
||||||
const {
|
const {
|
||||||
preferences: { isSidebarCollapsed },
|
preferences: { isSidebarCollapsed, language },
|
||||||
setPreference,
|
setPreference,
|
||||||
} = useCurrentUserPreferences();
|
} = useCurrentUserPreferences();
|
||||||
|
|
||||||
@ -159,13 +157,6 @@ const NavBar = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const language = useMemo(
|
|
||||||
() =>
|
|
||||||
(cookieStorage.getItem('i18next') as SupportedLocales) ||
|
|
||||||
SupportedLocales.English,
|
|
||||||
[]
|
|
||||||
);
|
|
||||||
|
|
||||||
const { socket } = useWebSocketConnector();
|
const { socket } = useWebSocketConnector();
|
||||||
|
|
||||||
const handleTaskNotificationRead = () => {
|
const handleTaskNotificationRead = () => {
|
||||||
@ -436,6 +427,7 @@ const NavBar = () => {
|
|||||||
|
|
||||||
const handleLanguageChange = useCallback(({ key }: MenuInfo) => {
|
const handleLanguageChange = useCallback(({ key }: MenuInfo) => {
|
||||||
i18next.changeLanguage(key);
|
i18next.changeLanguage(key);
|
||||||
|
setPreference({ language: key as SupportedLocales });
|
||||||
navigate(0);
|
navigate(0);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@ -519,10 +511,7 @@ const NavBar = () => {
|
|||||||
<Button
|
<Button
|
||||||
className="flex-center gap-2 p-x-xs font-medium"
|
className="flex-center gap-2 p-x-xs font-medium"
|
||||||
type="text">
|
type="text">
|
||||||
{upperCase(
|
{upperCase(language.split('-')[0])} <DropDownIcon width={12} />
|
||||||
(language || SupportedLocales.English).split('-')[0]
|
|
||||||
)}{' '}
|
|
||||||
<DropDownIcon width={12} />
|
|
||||||
</Button>
|
</Button>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
<Dropdown
|
<Dropdown
|
||||||
|
@ -20,7 +20,7 @@ import {
|
|||||||
} from '../../../constants/regex.constants';
|
} from '../../../constants/regex.constants';
|
||||||
import { PipelineType } from '../../../generated/entity/services/ingestionPipelines/ingestionPipeline';
|
import { PipelineType } from '../../../generated/entity/services/ingestionPipelines/ingestionPipeline';
|
||||||
import { fetchMarkdownFile } from '../../../rest/miscAPI';
|
import { fetchMarkdownFile } from '../../../rest/miscAPI';
|
||||||
import { SupportedLocales } from '../../../utils/i18next/i18nextUtil';
|
import { SupportedLocales } from '../../../utils/i18next/LocalUtil.interface';
|
||||||
import { getActiveFieldNameForAppDocs } from '../../../utils/ServiceUtils';
|
import { getActiveFieldNameForAppDocs } from '../../../utils/ServiceUtils';
|
||||||
import Loader from '../Loader/Loader';
|
import Loader from '../Loader/Loader';
|
||||||
import RichTextEditorPreviewer from '../RichTextEditor/RichTextEditorPreviewer';
|
import RichTextEditorPreviewer from '../RichTextEditor/RichTextEditorPreviewer';
|
||||||
|
@ -11,7 +11,6 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import i18next from 'i18next';
|
|
||||||
import { ReactComponent as GovernIcon } from '../assets/svg/bank.svg';
|
import { ReactComponent as GovernIcon } from '../assets/svg/bank.svg';
|
||||||
import { ReactComponent as ClassificationIcon } from '../assets/svg/classification.svg';
|
import { ReactComponent as ClassificationIcon } from '../assets/svg/classification.svg';
|
||||||
import { ReactComponent as ExploreIcon } from '../assets/svg/explore.svg';
|
import { ReactComponent as ExploreIcon } from '../assets/svg/explore.svg';
|
||||||
@ -39,48 +38,48 @@ export const SIDEBAR_NESTED_KEYS = {
|
|||||||
export const SIDEBAR_LIST: Array<LeftSidebarItem> = [
|
export const SIDEBAR_LIST: Array<LeftSidebarItem> = [
|
||||||
{
|
{
|
||||||
key: ROUTES.MY_DATA,
|
key: ROUTES.MY_DATA,
|
||||||
title: i18next.t('label.home'),
|
title: 'label.home',
|
||||||
redirect_url: ROUTES.MY_DATA,
|
redirect_url: ROUTES.MY_DATA,
|
||||||
icon: HomeIcon,
|
icon: HomeIcon,
|
||||||
dataTestId: `app-bar-item-${SidebarItem.HOME}`,
|
dataTestId: `app-bar-item-${SidebarItem.HOME}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: ROUTES.EXPLORE,
|
key: ROUTES.EXPLORE,
|
||||||
title: i18next.t('label.explore'),
|
title: 'label.explore',
|
||||||
redirect_url: ROUTES.EXPLORE,
|
redirect_url: ROUTES.EXPLORE,
|
||||||
icon: ExploreIcon,
|
icon: ExploreIcon,
|
||||||
dataTestId: `app-bar-item-${SidebarItem.EXPLORE}`,
|
dataTestId: `app-bar-item-${SidebarItem.EXPLORE}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: ROUTES.PLATFORM_LINEAGE,
|
key: ROUTES.PLATFORM_LINEAGE,
|
||||||
title: i18next.t('label.lineage'),
|
title: 'label.lineage',
|
||||||
redirect_url: ROUTES.PLATFORM_LINEAGE,
|
redirect_url: ROUTES.PLATFORM_LINEAGE,
|
||||||
icon: PlatformLineageIcon,
|
icon: PlatformLineageIcon,
|
||||||
dataTestId: `app-bar-item-${SidebarItem.LINEAGE}`,
|
dataTestId: `app-bar-item-${SidebarItem.LINEAGE}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: ROUTES.OBSERVABILITY,
|
key: ROUTES.OBSERVABILITY,
|
||||||
title: i18next.t('label.observability'),
|
title: 'label.observability',
|
||||||
icon: ObservabilityIcon,
|
icon: ObservabilityIcon,
|
||||||
dataTestId: SidebarItem.OBSERVABILITY,
|
dataTestId: SidebarItem.OBSERVABILITY,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
key: ROUTES.DATA_QUALITY,
|
key: ROUTES.DATA_QUALITY,
|
||||||
title: i18next.t('label.data-quality'),
|
title: 'label.data-quality',
|
||||||
redirect_url: ROUTES.DATA_QUALITY,
|
redirect_url: ROUTES.DATA_QUALITY,
|
||||||
icon: DataQualityIcon,
|
icon: DataQualityIcon,
|
||||||
dataTestId: `app-bar-item-${SidebarItem.DATA_QUALITY}`,
|
dataTestId: `app-bar-item-${SidebarItem.DATA_QUALITY}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: ROUTES.INCIDENT_MANAGER,
|
key: ROUTES.INCIDENT_MANAGER,
|
||||||
title: i18next.t('label.incident-manager'),
|
title: 'label.incident-manager',
|
||||||
redirect_url: ROUTES.INCIDENT_MANAGER,
|
redirect_url: ROUTES.INCIDENT_MANAGER,
|
||||||
icon: IncidentMangerIcon,
|
icon: IncidentMangerIcon,
|
||||||
dataTestId: `app-bar-item-${SidebarItem.INCIDENT_MANAGER}`,
|
dataTestId: `app-bar-item-${SidebarItem.INCIDENT_MANAGER}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: ROUTES.OBSERVABILITY_ALERTS,
|
key: ROUTES.OBSERVABILITY_ALERTS,
|
||||||
title: i18next.t('label.alert-plural'),
|
title: 'label.alert-plural',
|
||||||
redirect_url: ROUTES.OBSERVABILITY_ALERTS,
|
redirect_url: ROUTES.OBSERVABILITY_ALERTS,
|
||||||
icon: AlertIcon,
|
icon: AlertIcon,
|
||||||
dataTestId: `app-bar-item-${SidebarItem.OBSERVABILITY_ALERT}`,
|
dataTestId: `app-bar-item-${SidebarItem.OBSERVABILITY_ALERT}`,
|
||||||
@ -89,7 +88,7 @@ export const SIDEBAR_LIST: Array<LeftSidebarItem> = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: ROUTES.DATA_INSIGHT,
|
key: ROUTES.DATA_INSIGHT,
|
||||||
title: i18next.t('label.insight-plural'),
|
title: 'label.insight-plural',
|
||||||
redirect_url: ROUTES.DATA_INSIGHT_WITH_TAB.replace(
|
redirect_url: ROUTES.DATA_INSIGHT_WITH_TAB.replace(
|
||||||
PLACEHOLDER_ROUTE_TAB,
|
PLACEHOLDER_ROUTE_TAB,
|
||||||
DataInsightTabs.DATA_ASSETS
|
DataInsightTabs.DATA_ASSETS
|
||||||
@ -99,34 +98,34 @@ export const SIDEBAR_LIST: Array<LeftSidebarItem> = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: ROUTES.DOMAIN,
|
key: ROUTES.DOMAIN,
|
||||||
title: i18next.t('label.domain-plural'),
|
title: 'label.domain-plural',
|
||||||
redirect_url: ROUTES.DOMAIN,
|
redirect_url: ROUTES.DOMAIN,
|
||||||
icon: DomainsIcon,
|
icon: DomainsIcon,
|
||||||
dataTestId: `app-bar-item-${SidebarItem.DOMAIN}`,
|
dataTestId: `app-bar-item-${SidebarItem.DOMAIN}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'governance',
|
key: 'governance',
|
||||||
title: i18next.t('label.govern'),
|
title: 'label.govern',
|
||||||
icon: GovernIcon,
|
icon: GovernIcon,
|
||||||
dataTestId: SidebarItem.GOVERNANCE,
|
dataTestId: SidebarItem.GOVERNANCE,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
key: ROUTES.GLOSSARY,
|
key: ROUTES.GLOSSARY,
|
||||||
title: i18next.t('label.glossary'),
|
title: 'label.glossary',
|
||||||
redirect_url: ROUTES.GLOSSARY,
|
redirect_url: ROUTES.GLOSSARY,
|
||||||
icon: GlossaryIcon,
|
icon: GlossaryIcon,
|
||||||
dataTestId: `app-bar-item-${SidebarItem.GLOSSARY}`,
|
dataTestId: `app-bar-item-${SidebarItem.GLOSSARY}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: ROUTES.TAGS,
|
key: ROUTES.TAGS,
|
||||||
title: i18next.t('label.classification'),
|
title: 'label.classification',
|
||||||
redirect_url: ROUTES.TAGS,
|
redirect_url: ROUTES.TAGS,
|
||||||
icon: ClassificationIcon,
|
icon: ClassificationIcon,
|
||||||
dataTestId: `app-bar-item-${SidebarItem.TAGS}`,
|
dataTestId: `app-bar-item-${SidebarItem.TAGS}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: ROUTES.METRICS,
|
key: ROUTES.METRICS,
|
||||||
title: i18next.t('label.metric-plural'),
|
title: 'label.metric-plural',
|
||||||
redirect_url: ROUTES.METRICS,
|
redirect_url: ROUTES.METRICS,
|
||||||
icon: MetricIcon,
|
icon: MetricIcon,
|
||||||
dataTestId: `app-bar-item-${SidebarItem.METRICS}`,
|
dataTestId: `app-bar-item-${SidebarItem.METRICS}`,
|
||||||
@ -137,7 +136,7 @@ export const SIDEBAR_LIST: Array<LeftSidebarItem> = [
|
|||||||
|
|
||||||
export const SETTING_ITEM = {
|
export const SETTING_ITEM = {
|
||||||
key: ROUTES.SETTINGS,
|
key: ROUTES.SETTINGS,
|
||||||
title: i18next.t('label.setting-plural'),
|
title: 'label.setting-plural',
|
||||||
redirect_url: ROUTES.SETTINGS,
|
redirect_url: ROUTES.SETTINGS,
|
||||||
icon: SettingsIcon,
|
icon: SettingsIcon,
|
||||||
dataTestId: `app-bar-item-${SidebarItem.SETTINGS}`,
|
dataTestId: `app-bar-item-${SidebarItem.SETTINGS}`,
|
||||||
@ -145,7 +144,7 @@ export const SETTING_ITEM = {
|
|||||||
|
|
||||||
export const LOGOUT_ITEM = {
|
export const LOGOUT_ITEM = {
|
||||||
key: SidebarItem.LOGOUT,
|
key: SidebarItem.LOGOUT,
|
||||||
title: i18next.t('label.logout'),
|
title: 'label.logout',
|
||||||
icon: LogoutIcon,
|
icon: LogoutIcon,
|
||||||
dataTestId: `app-bar-item-${SidebarItem.LOGOUT}`,
|
dataTestId: `app-bar-item-${SidebarItem.LOGOUT}`,
|
||||||
};
|
};
|
||||||
|
@ -13,10 +13,13 @@
|
|||||||
|
|
||||||
import { create } from 'zustand';
|
import { create } from 'zustand';
|
||||||
import { createJSONStorage, persist } from 'zustand/middleware';
|
import { createJSONStorage, persist } from 'zustand/middleware';
|
||||||
|
import { detectBrowserLanguage } from '../../utils/i18next/LocalUtil';
|
||||||
|
import { SupportedLocales } from '../../utils/i18next/LocalUtil.interface';
|
||||||
import { useApplicationStore } from '../useApplicationStore';
|
import { useApplicationStore } from '../useApplicationStore';
|
||||||
|
|
||||||
export interface UserPreferences {
|
export interface UserPreferences {
|
||||||
isSidebarCollapsed: boolean;
|
isSidebarCollapsed: boolean;
|
||||||
|
language: SupportedLocales;
|
||||||
selectedEntityTableColumns: Record<string, string[]>;
|
selectedEntityTableColumns: Record<string, string[]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,6 +35,7 @@ interface Store {
|
|||||||
|
|
||||||
const defaultPreferences: UserPreferences = {
|
const defaultPreferences: UserPreferences = {
|
||||||
isSidebarCollapsed: false,
|
isSidebarCollapsed: false,
|
||||||
|
language: detectBrowserLanguage(),
|
||||||
selectedEntityTableColumns: {},
|
selectedEntityTableColumns: {},
|
||||||
// Add default values for other preferences
|
// Add default values for other preferences
|
||||||
};
|
};
|
||||||
|
@ -155,7 +155,7 @@ export const SettingsNavigationPage = ({
|
|||||||
|
|
||||||
const titleRenderer = (node: TreeDataNode) => (
|
const titleRenderer = (node: TreeDataNode) => (
|
||||||
<div className="space-between">
|
<div className="space-between">
|
||||||
{node.title as string}
|
{t(node.title as string)}
|
||||||
<Switch
|
<Switch
|
||||||
checked={!hiddenKeys.includes(node.key as string)}
|
checked={!hiddenKeys.includes(node.key as string)}
|
||||||
onChange={(checked) => handleRemoveToggle(checked, node.key as string)}
|
onChange={(checked) => handleRemoveToggle(checked, node.key as string)}
|
||||||
|
@ -95,6 +95,7 @@ jest.mock('utils/i18next/LocalUtil', () => ({
|
|||||||
useTranslation: jest.fn().mockReturnValue({
|
useTranslation: jest.fn().mockReturnValue({
|
||||||
t: (key) => key,
|
t: (key) => key,
|
||||||
}),
|
}),
|
||||||
|
detectBrowserLanguage: jest.fn().mockReturnValue('en-US'),
|
||||||
t: (key) => key,
|
t: (key) => key,
|
||||||
dir: jest.fn().mockReturnValue('ltr'),
|
dir: jest.fn().mockReturnValue('ltr'),
|
||||||
}));
|
}));
|
||||||
|
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2025 Collate.
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
// to remove circular dependency
|
||||||
|
export enum SupportedLocales {
|
||||||
|
English = 'en-US',
|
||||||
|
한국어 = 'ko-KR',
|
||||||
|
Français = 'fr-FR',
|
||||||
|
简体中文 = 'zh-CN',
|
||||||
|
日本語 = 'ja-JP',
|
||||||
|
'Português (Brasil)' = 'pt-BR',
|
||||||
|
'Português (Portugal)' = 'pt-PT',
|
||||||
|
Español = 'es-ES',
|
||||||
|
Galego = 'gl-ES',
|
||||||
|
Русский = 'ru-RU',
|
||||||
|
Deutsch = 'de-DE',
|
||||||
|
Hebrew = 'he-HE',
|
||||||
|
Nederlands = 'nl-NL',
|
||||||
|
Persian = 'pr-PR',
|
||||||
|
Thai = 'th-TH',
|
||||||
|
मराठी = 'mr-IN',
|
||||||
|
Türkçe = 'tr-TR',
|
||||||
|
}
|
@ -14,7 +14,27 @@
|
|||||||
import i18n, { t as i18nextT } from 'i18next';
|
import i18n, { t as i18nextT } from 'i18next';
|
||||||
import LanguageDetector from 'i18next-browser-languagedetector';
|
import LanguageDetector from 'i18next-browser-languagedetector';
|
||||||
import { initReactI18next } from 'react-i18next';
|
import { initReactI18next } from 'react-i18next';
|
||||||
import { getInitOptions } from './i18nextUtil';
|
import { getInitOptions, languageMap } from './i18nextUtil';
|
||||||
|
import { SupportedLocales } from './LocalUtil.interface';
|
||||||
|
|
||||||
|
// Function to detect browser language
|
||||||
|
export const detectBrowserLanguage = (): SupportedLocales => {
|
||||||
|
const browserLang = navigator.language;
|
||||||
|
const browserLangs = navigator.languages || [browserLang];
|
||||||
|
let browserLanguage = undefined;
|
||||||
|
for (const lang of browserLangs) {
|
||||||
|
const langCode = lang.split('-')[0];
|
||||||
|
|
||||||
|
if (languageMap[langCode]) {
|
||||||
|
browserLanguage = languageMap[langCode];
|
||||||
|
|
||||||
|
return browserLanguage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// English is the default language when we don't support browser language
|
||||||
|
return browserLanguage ?? SupportedLocales.English;
|
||||||
|
};
|
||||||
|
|
||||||
// Initialize i18next (language)
|
// Initialize i18next (language)
|
||||||
i18n
|
i18n
|
||||||
|
@ -30,26 +30,7 @@ import ruRU from '../../locale/languages/ru-ru.json';
|
|||||||
import thTH from '../../locale/languages/th-th.json';
|
import thTH from '../../locale/languages/th-th.json';
|
||||||
import trTR from '../../locale/languages/tr-tr.json';
|
import trTR from '../../locale/languages/tr-tr.json';
|
||||||
import zhCN from '../../locale/languages/zh-cn.json';
|
import zhCN from '../../locale/languages/zh-cn.json';
|
||||||
|
import { SupportedLocales } from './LocalUtil.interface';
|
||||||
export enum SupportedLocales {
|
|
||||||
English = 'en-US',
|
|
||||||
한국어 = 'ko-KR',
|
|
||||||
Français = 'fr-FR',
|
|
||||||
简体中文 = 'zh-CN',
|
|
||||||
日本語 = 'ja-JP',
|
|
||||||
'Português (Brasil)' = 'pt-BR',
|
|
||||||
'Português (Portugal)' = 'pt-PT',
|
|
||||||
Español = 'es-ES',
|
|
||||||
Galego = 'gl-ES',
|
|
||||||
Русский = 'ru-RU',
|
|
||||||
Deutsch = 'de-DE',
|
|
||||||
Hebrew = 'he-HE',
|
|
||||||
Nederlands = 'nl-NL',
|
|
||||||
Persian = 'pr-PR',
|
|
||||||
Thai = 'th-TH',
|
|
||||||
मराठी = 'mr-IN',
|
|
||||||
Türkçe = 'tr-TR',
|
|
||||||
}
|
|
||||||
|
|
||||||
export const languageSelectOptions = map(SupportedLocales, (value, key) => ({
|
export const languageSelectOptions = map(SupportedLocales, (value, key) => ({
|
||||||
label: `${key} - ${upperCase(value.split('-')[0])}`,
|
label: `${key} - ${upperCase(value.split('-')[0])}`,
|
||||||
@ -110,3 +91,23 @@ export const getCurrentLocaleForConstrue = () => {
|
|||||||
|
|
||||||
return i18next.resolvedLanguage.split('-')[0];
|
return i18next.resolvedLanguage.split('-')[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Map common language codes to supported locales
|
||||||
|
export const languageMap: Record<string, SupportedLocales> = {
|
||||||
|
mr: SupportedLocales.मराठी, // Marathi
|
||||||
|
en: SupportedLocales.English,
|
||||||
|
ko: SupportedLocales.한국어,
|
||||||
|
fr: SupportedLocales.Français,
|
||||||
|
zh: SupportedLocales.简体中文,
|
||||||
|
ja: SupportedLocales.日本語,
|
||||||
|
pt: SupportedLocales['Português (Brasil)'], // Default to Brazilian Portuguese
|
||||||
|
es: SupportedLocales.Español,
|
||||||
|
gl: SupportedLocales.Galego,
|
||||||
|
ru: SupportedLocales.Русский,
|
||||||
|
de: SupportedLocales.Deutsch,
|
||||||
|
he: SupportedLocales.Hebrew,
|
||||||
|
nl: SupportedLocales.Nederlands,
|
||||||
|
pr: SupportedLocales.Persian,
|
||||||
|
th: SupportedLocales.Thai,
|
||||||
|
tr: SupportedLocales.Türkçe,
|
||||||
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user