mirror of
https://github.com/kremalicious/umami.git
synced 2024-12-22 09:13:37 +01:00
Dynamically fetch language bundles at runtime.
This commit is contained in:
parent
73e83ad767
commit
f91cc82c82
1
.gitignore
vendored
1
.gitignore
vendored
@ -17,6 +17,7 @@
|
||||
/build
|
||||
/public/umami.js
|
||||
/public/geo
|
||||
/public/lang
|
||||
/lang-compiled
|
||||
|
||||
# misc
|
||||
|
@ -27,7 +27,7 @@ import styles from './Calendar.module.css';
|
||||
import Icon from './Icon';
|
||||
|
||||
export default function Calendar({ date, minDate, maxDate, onChange }) {
|
||||
const [locale] = useLocale();
|
||||
const { locale } = useLocale();
|
||||
const [selectMonth, setSelectMonth] = useState(false);
|
||||
const [selectYear, setSelectYear] = useState(false);
|
||||
|
||||
|
@ -55,7 +55,7 @@ const filterOptions = [
|
||||
];
|
||||
|
||||
function DateFilter({ value, startDate, endDate, onChange, className }) {
|
||||
const [locale] = useLocale();
|
||||
const { locale } = useLocale();
|
||||
const [showPicker, setShowPicker] = useState(false);
|
||||
const displayValue =
|
||||
value === 'custom' ? (
|
||||
@ -102,7 +102,7 @@ function DateFilter({ value, startDate, endDate, onChange, className }) {
|
||||
}
|
||||
|
||||
const CustomRange = ({ startDate, endDate, onClick }) => {
|
||||
const [locale] = useLocale();
|
||||
const { locale } = useLocale();
|
||||
|
||||
function handleClick(e) {
|
||||
e.stopPropagation();
|
||||
|
@ -12,7 +12,7 @@ import useLocale from 'hooks/useLocale';
|
||||
|
||||
function RefreshButton({ websiteId }) {
|
||||
const dispatch = useDispatch();
|
||||
const [locale] = useLocale();
|
||||
const { locale } = useLocale();
|
||||
const [dateRange] = useDateRange(websiteId);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const completed = useSelector(state => state.queries[`/api/website/${websiteId}/stats`]);
|
||||
|
@ -24,7 +24,7 @@ function WorldMap({ data, className }) {
|
||||
}),
|
||||
[theme],
|
||||
);
|
||||
const [locale] = useLocale();
|
||||
const { locale } = useLocale();
|
||||
const countryNames = useCountryNames(locale);
|
||||
|
||||
function getFillColor(code) {
|
||||
|
@ -9,7 +9,7 @@ import { rtlLocales } from 'lib/lang';
|
||||
|
||||
export default function Footer() {
|
||||
const { current } = useVersion();
|
||||
const [locale] = useLocale();
|
||||
const { locale } = useLocale();
|
||||
|
||||
return (
|
||||
<footer className="container" dir={rtlLocales.includes(locale) ? 'rtl' : 'ltr'}>
|
||||
|
@ -19,7 +19,7 @@ import Bars from 'assets/bars.svg';
|
||||
export default function Header() {
|
||||
const user = useSelector(state => state.user);
|
||||
const [active, setActive] = useState(false);
|
||||
const [locale] = useLocale();
|
||||
const { locale } = useLocale();
|
||||
|
||||
function handleClick() {
|
||||
setActive(state => !state);
|
||||
|
@ -6,7 +6,7 @@ import useLocale from 'hooks/useLocale';
|
||||
import { rtlLocales } from 'lib/lang';
|
||||
|
||||
export default function Layout({ title, children, header = true, footer = true }) {
|
||||
const [locale] = useLocale();
|
||||
const { locale } = useLocale();
|
||||
const dir = rtlLocales.includes(locale) ? 'rtl' : 'ltr';
|
||||
|
||||
return (
|
||||
|
@ -27,7 +27,7 @@ export default function BarChart({
|
||||
const canvas = useRef();
|
||||
const chart = useRef();
|
||||
const [tooltip, setTooltip] = useState(null);
|
||||
const [locale] = useLocale();
|
||||
const { locale } = useLocale();
|
||||
const [theme] = useTheme();
|
||||
const forceUpdate = useForceUpdate();
|
||||
|
||||
|
@ -6,7 +6,7 @@ import useCountryNames from 'hooks/useCountryNames';
|
||||
import useLocale from 'hooks/useLocale';
|
||||
|
||||
export default function CountriesTable({ websiteId, onDataLoad, ...props }) {
|
||||
const [locale] = useLocale();
|
||||
const { locale } = useLocale();
|
||||
const countryNames = useCountryNames(locale);
|
||||
|
||||
function renderLabel({ x }) {
|
||||
|
@ -6,7 +6,7 @@ import styles from './Legend.module.css';
|
||||
import useForceUpdate from '../../hooks/useForceUpdate';
|
||||
|
||||
export default function Legend({ chart }) {
|
||||
const [locale] = useLocale();
|
||||
const { locale } = useLocale();
|
||||
const forceUpdate = useForceUpdate();
|
||||
|
||||
function handleClick(index) {
|
||||
|
@ -31,7 +31,7 @@ const TYPE_ICONS = {
|
||||
|
||||
export default function RealtimeLog({ data, websites, websiteId }) {
|
||||
const intl = useIntl();
|
||||
const [locale] = useLocale();
|
||||
const { locale } = useLocale();
|
||||
const countryNames = useCountryNames(locale);
|
||||
const [filter, setFilter] = useState(TYPE_ALL);
|
||||
|
||||
|
@ -29,7 +29,7 @@ function filterWebsite(data, id) {
|
||||
}
|
||||
|
||||
export default function RealtimeDashboard() {
|
||||
const [locale] = useLocale();
|
||||
const { locale } = useLocale();
|
||||
const countryNames = useCountryNames(locale);
|
||||
const [data, setData] = useState();
|
||||
const [websiteId, setWebsiteId] = useState(0);
|
||||
|
@ -9,7 +9,7 @@ import styles from './DateRangeSetting.module.css';
|
||||
import useLocale from 'hooks/useLocale';
|
||||
|
||||
export default function DateRangeSetting() {
|
||||
const [locale] = useLocale();
|
||||
const { locale } = useLocale();
|
||||
const [dateRange, setDateRange] = useDateRange();
|
||||
const { startDate, endDate, value } = dateRange;
|
||||
|
||||
|
@ -1,15 +1,16 @@
|
||||
import React from 'react';
|
||||
import { menuOptions } from 'lib/lang';
|
||||
import { languages } from 'lib/lang';
|
||||
import useLocale from 'hooks/useLocale';
|
||||
import MenuButton from 'components/common/MenuButton';
|
||||
import Globe from 'assets/globe.svg';
|
||||
import styles from './LanguageButton.module.css';
|
||||
|
||||
export default function LanguageButton() {
|
||||
const [locale, setLocale] = useLocale();
|
||||
const { locale, saveLocale } = useLocale();
|
||||
const menuOptions = Object.keys(languages).map(key => ({ ...languages[key], value: key }));
|
||||
|
||||
function handleSelect(value) {
|
||||
setLocale(value);
|
||||
saveLocale(value);
|
||||
}
|
||||
|
||||
switch (locale) {
|
||||
|
@ -9,7 +9,7 @@ import useLocale from './useLocale';
|
||||
|
||||
export default function useDateRange(websiteId, defaultDateRange = DEFAULT_DATE_RANGE) {
|
||||
const dispatch = useDispatch();
|
||||
const [locale] = useLocale();
|
||||
const { locale } = useLocale();
|
||||
const dateRange = useSelector(state => state.websites[websiteId]?.dateRange);
|
||||
const forceUpdate = useForceUpdate();
|
||||
|
||||
|
@ -1,16 +1,49 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { setLocale } from 'redux/actions/app';
|
||||
import { setItem } from 'lib/web';
|
||||
import { useRouter } from 'next/router';
|
||||
import { get, setItem } from 'lib/web';
|
||||
import { LOCALE_CONFIG } from 'lib/constants';
|
||||
import useForceUpdate from 'hooks/useForceUpdate';
|
||||
import enUS from 'public/lang/en-US.json';
|
||||
|
||||
const messages = {
|
||||
'en-US': enUS,
|
||||
};
|
||||
|
||||
export default function useLocale() {
|
||||
const locale = useSelector(state => state.app.locale);
|
||||
const dispatch = useDispatch();
|
||||
const { basePath } = useRouter();
|
||||
const forceUpdate = useForceUpdate();
|
||||
|
||||
function saveLocale(value) {
|
||||
setItem(LOCALE_CONFIG, value);
|
||||
dispatch(setLocale(value));
|
||||
async function loadMessages(locale) {
|
||||
const { ok, data } = await get(`${basePath}/lang/${locale}.json`);
|
||||
|
||||
if (ok) {
|
||||
messages[locale] = data;
|
||||
}
|
||||
}
|
||||
|
||||
return [locale, saveLocale];
|
||||
async function saveLocale(value) {
|
||||
if (!messages[value]) {
|
||||
await loadMessages(value);
|
||||
}
|
||||
|
||||
setItem(LOCALE_CONFIG, value);
|
||||
|
||||
if (locale !== value) {
|
||||
dispatch(setLocale(value));
|
||||
} else {
|
||||
forceUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!messages[locale]) {
|
||||
saveLocale(locale);
|
||||
}
|
||||
}, [locale]);
|
||||
|
||||
return { locale, saveLocale, messages };
|
||||
}
|
||||
|
141
lib/lang.js
141
lib/lang.js
@ -33,76 +33,42 @@ import {
|
||||
ca,
|
||||
hu,
|
||||
} from 'date-fns/locale';
|
||||
import arSAMessages from 'lang-compiled/ar-SA.json';
|
||||
import enMessages from 'lang-compiled/en-US.json';
|
||||
import nlMessages from 'lang-compiled/nl-NL.json';
|
||||
import zhCNMessages from 'lang-compiled/zh-CN.json';
|
||||
import zhTWMessages from 'lang-compiled/zh-TW.json';
|
||||
import trTRMessages from 'lang-compiled/tr-TR.json';
|
||||
import ruRUMessages from 'lang-compiled/ru-RU.json';
|
||||
import deDEMessages from 'lang-compiled/de-DE.json';
|
||||
import jaMessages from 'lang-compiled/ja-JP.json';
|
||||
import esMXMessages from 'lang-compiled/es-MX.json';
|
||||
import frMessages from 'lang-compiled/fr-FR.json';
|
||||
import mnMNMessages from 'lang-compiled/mn-MN.json';
|
||||
import daMessages from 'lang-compiled/da-DK.json';
|
||||
import svMessages from 'lang-compiled/sv-SE.json';
|
||||
import grMessages from 'lang-compiled/el-GR.json';
|
||||
import foMessages from 'lang-compiled/fo-FO.json';
|
||||
import ptMessages from 'lang-compiled/pt-PT.json';
|
||||
import ptBRMessages from 'lang-compiled/pt-BR.json';
|
||||
import roMessages from 'lang-compiled/ro-RO.json';
|
||||
import nbNOMessages from 'lang-compiled/nb-NO.json';
|
||||
import idMessages from 'lang-compiled/id-ID.json';
|
||||
import ukMessages from 'lang-compiled/uk-UA.json';
|
||||
import fiMessages from 'lang-compiled/fi-FI.json';
|
||||
import csMessages from 'lang-compiled/cs-CZ.json';
|
||||
import skMessages from 'lang-compiled/sk-SK.json';
|
||||
import plMessages from 'lang-compiled/pl-PL.json';
|
||||
import taMessages from 'lang-compiled/ta-IN.json';
|
||||
import hiMessages from 'lang-compiled/hi-IN.json';
|
||||
import heMessages from 'lang-compiled/he-IL.json';
|
||||
import itMessages from 'lang-compiled/it-IT.json';
|
||||
import faIRMessages from 'lang-compiled/fa-IR.json';
|
||||
import msMYMessages from 'lang-compiled/ms-MY.json';
|
||||
import caMessages from 'lang-compiled/ca-ES.json';
|
||||
import huMessages from 'lang-compiled/hu-HU.json';
|
||||
|
||||
export const messages = {
|
||||
'ar-SA': arSAMessages,
|
||||
'en-US': enMessages,
|
||||
'nl-NL': nlMessages,
|
||||
'zh-CN': zhCNMessages,
|
||||
'zh-TW': zhTWMessages,
|
||||
'de-DE': deDEMessages,
|
||||
'ru-RU': ruRUMessages,
|
||||
'tr-TR': trTRMessages,
|
||||
'ja-JP': jaMessages,
|
||||
'es-MX': esMXMessages,
|
||||
'fr-FR': frMessages,
|
||||
'mn-MN': mnMNMessages,
|
||||
'da-DK': daMessages,
|
||||
'sv-SE': svMessages,
|
||||
'el-GR': grMessages,
|
||||
'fo-FO': foMessages,
|
||||
'pt-PT': ptMessages,
|
||||
'pt-BR': ptBRMessages,
|
||||
'ro-RO': roMessages,
|
||||
'nb-NO': nbNOMessages,
|
||||
'id-ID': idMessages,
|
||||
'uk-UA': ukMessages,
|
||||
'fi-FI': fiMessages,
|
||||
'cs-CZ': csMessages,
|
||||
'sk-SK': skMessages,
|
||||
'pl-PL': plMessages,
|
||||
'ta-IN': taMessages,
|
||||
'hi-IN': hiMessages,
|
||||
'he-IL': heMessages,
|
||||
'it-IT': itMessages,
|
||||
'fa-IR': faIRMessages,
|
||||
'ms-MY': msMYMessages,
|
||||
'ca-ES': caMessages,
|
||||
'hu-HU': huMessages,
|
||||
export const languages = {
|
||||
'ar-SA': { label: 'العربية', display: 'ar' },
|
||||
'zh-CN': { label: '中文', display: 'cn' },
|
||||
'zh-TW': { label: '中文(繁體)', display: 'tw' },
|
||||
'ca-ES': { label: 'Català', display: 'ca' },
|
||||
'cs-CZ': { label: 'Čeština', display: 'cs' },
|
||||
'da-DK': { label: 'Dansk', display: 'da' },
|
||||
'de-DE': { label: 'Deutsch', display: 'de' },
|
||||
'en-US': { label: 'English', display: 'en' },
|
||||
'es-MX': { label: 'Español', display: 'es' },
|
||||
'fa-IR': { label: 'فارسی', display: 'fa' },
|
||||
'fo-FO': { label: 'Føroyskt', display: 'fo' },
|
||||
'fr-FR': { label: 'Français', display: 'fr' },
|
||||
'el-GR': { label: 'Ελληνικά', display: 'el' },
|
||||
'he-IL': { label: 'עברית', display: 'he' },
|
||||
'hi-IN': { label: 'हिन्दी', display: 'hi' },
|
||||
'hu-HU': { label: 'Hungarian', display: 'hu' },
|
||||
'it-IT': { label: 'Italiano', display: 'it' },
|
||||
'id-ID': { label: 'Bahasa Indonesia', display: 'id' },
|
||||
'ja-JP': { label: '日本語', display: 'ja' },
|
||||
'ms-MY': { label: 'Malay', display: 'ms' },
|
||||
'mn-MN': { label: 'Монгол', display: 'mn' },
|
||||
'nl-NL': { label: 'Nederlands', display: 'nl' },
|
||||
'nb-NO': { label: 'Norsk Bokmål', display: 'nb' },
|
||||
'pl-PL': { label: 'Polski', display: 'pl' },
|
||||
'pt-PT': { label: 'Português', display: 'pt' },
|
||||
'pt-BR': { label: 'Português do Brasil', display: 'pt-BR' },
|
||||
'ru-RU': { label: 'Русский', display: 'ru' },
|
||||
'ro-RO': { label: 'Română', display: 'ro' },
|
||||
'sk-SK': { label: 'Slovenčina', display: 'sk' },
|
||||
'fi-FI': { label: 'Suomi', display: 'fi' },
|
||||
'sv-SE': { label: 'Svenska', display: 'sv' },
|
||||
'ta-IN': { label: 'தமிழ்', display: 'ta' },
|
||||
'tr-TR': { label: 'Türkçe', display: 'tr' },
|
||||
'uk-UA': { label: 'українська', display: 'uk' },
|
||||
};
|
||||
|
||||
export const rtlLocales = ['ar-SA', 'fa-IR'];
|
||||
@ -143,40 +109,3 @@ export const dateLocales = {
|
||||
'ca-ES': ca,
|
||||
'hu-HU': hu,
|
||||
};
|
||||
|
||||
export const menuOptions = [
|
||||
{ label: 'العربية', value: 'ar-SA', display: 'ar' },
|
||||
{ label: '中文', value: 'zh-CN', display: 'cn' },
|
||||
{ label: '中文(繁體)', value: 'zh-TW', display: 'tw' },
|
||||
{ label: 'Català', value: 'ca-ES', display: 'ca' },
|
||||
{ label: 'Čeština', value: 'cs-CZ', display: 'cs' },
|
||||
{ label: 'Dansk', value: 'da-DK', display: 'da' },
|
||||
{ label: 'Deutsch', value: 'de-DE', display: 'de' },
|
||||
{ label: 'English', value: 'en-US', display: 'en' },
|
||||
{ label: 'Español', value: 'es-MX', display: 'es' },
|
||||
{ label: 'فارسی', value: 'fa-IR', display: 'fa' },
|
||||
{ label: 'Føroyskt', value: 'fo-FO', display: 'fo' },
|
||||
{ label: 'Français', value: 'fr-FR', display: 'fr' },
|
||||
{ label: 'Ελληνικά', value: 'el-GR', display: 'el' },
|
||||
{ label: 'עברית', value: 'he-IL', display: 'he' },
|
||||
{ label: 'हिन्दी', value: 'hi-IN', display: 'hi' },
|
||||
{ label: 'Hungarian', value: 'hu-HU', display: 'hu' },
|
||||
{ label: 'Italiano', value: 'it-IT', display: 'it' },
|
||||
{ label: 'Bahasa Indonesia', value: 'id-ID', display: 'id' },
|
||||
{ label: '日本語', value: 'ja-JP', display: 'ja' },
|
||||
{ label: 'Malay', value: 'ms-MY', display: 'ms' },
|
||||
{ label: 'Монгол', value: 'mn-MN', display: 'mn' },
|
||||
{ label: 'Nederlands', value: 'nl-NL', display: 'nl' },
|
||||
{ label: 'Norsk Bokmål', value: 'nb-NO', display: 'nb' },
|
||||
{ label: 'Polski', value: 'pl-PL', display: 'pl' },
|
||||
{ label: 'Português', value: 'pt-PT', display: 'pt' },
|
||||
{ label: 'Português do Brasil', value: 'pt-BR', display: 'pt-BR' },
|
||||
{ label: 'Русский', value: 'ru-RU', display: 'ru' },
|
||||
{ label: 'Română', value: 'ro-RO', display: 'ro' },
|
||||
{ label: 'Slovenčina', value: 'sk-SK', display: 'sk' },
|
||||
{ label: 'Suomi', value: 'fi-FI', display: 'fi' },
|
||||
{ label: 'Svenska', value: 'sv-SE', display: 'sv' },
|
||||
{ label: 'தமிழ்', value: 'ta-IN', display: 'ta' },
|
||||
{ label: 'Türkçe', value: 'tr-TR', display: 'tr' },
|
||||
{ label: 'українська', value: 'uk-UA', display: 'uk' },
|
||||
];
|
||||
|
@ -30,7 +30,7 @@
|
||||
"extract-lang": "formatjs extract '{pages,components}/**/*.js' --out-file build/messages.json",
|
||||
"merge-lang": "node scripts/merge-lang.js",
|
||||
"format-lang": "node scripts/format-lang.js",
|
||||
"compile-lang": "formatjs compile-folder --ast build lang-compiled",
|
||||
"compile-lang": "formatjs compile-folder --ast build public/lang",
|
||||
"check-lang": "node scripts/check-lang.js",
|
||||
"download-country-names": "node scripts/download-country-names.js",
|
||||
"loadtest": "node scripts/loadtest.js",
|
||||
|
@ -6,7 +6,6 @@ import { Provider } from 'react-redux';
|
||||
import { useStore } from 'redux/store';
|
||||
import useLocale from 'hooks/useLocale';
|
||||
import useForceSSL from 'hooks/useForceSSL';
|
||||
import { messages } from 'lib/lang';
|
||||
import 'styles/variables.css';
|
||||
import 'styles/bootstrap-grid.css';
|
||||
import 'styles/index.css';
|
||||
@ -14,7 +13,7 @@ import '@fontsource/inter/400.css';
|
||||
import '@fontsource/inter/600.css';
|
||||
|
||||
const Intl = ({ children }) => {
|
||||
const [locale] = useLocale();
|
||||
const { locale, messages } = useLocale();
|
||||
|
||||
const Wrapper = ({ children }) => <span className={locale}>{children}</span>;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user