Merge pull request #728 from mikecao/dev

v1.19.0
This commit is contained in:
Mike Cao 2021-07-16 00:25:42 -07:00 committed by GitHub
commit a2fdab6c9b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 959 additions and 569 deletions

1
.gitignore vendored
View File

@ -17,6 +17,7 @@
/build
/public/umami.js
/public/geo
/public/lang
/lang-compiled
# misc

View File

@ -10,7 +10,7 @@ A detailed getting started guide can be found at [https://umami.is/docs/](https:
### Requirements
- A server with Node.js 10.13 or newer
- A server with Node.js 12 or newer
- A database (MySQL or Postgresql)
### Get the source code and install packages

View File

@ -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);

View File

@ -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();

View File

@ -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`]);

View File

@ -24,7 +24,7 @@ function WorldMap({ data, className }) {
}),
[theme],
);
const [locale] = useLocale();
const { locale } = useLocale();
const countryNames = useCountryNames(locale);
function getFillColor(code) {

View File

@ -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'}>

View File

@ -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);

View File

@ -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 (

View File

@ -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();

View File

@ -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 }) {

View File

@ -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) {

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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) {

View File

@ -11,6 +11,7 @@ services:
HASH_SALT: replace-me-with-a-random-string
depends_on:
- db
restart: always
db:
image: postgres:12-alpine
environment:
@ -20,5 +21,6 @@ services:
volumes:
- ./sql/schema.postgresql.sql:/docker-entrypoint-initdb.d/schema.postgresql.sql:ro
- umami-db-data:/var/lib/postgresql/data
restart: always
volumes:
umami-db-data:

View File

@ -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();

View File

@ -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 };
}

100
lang/hu-HU.json Normal file
View File

@ -0,0 +1,100 @@
{
"label.accounts": "Fiókok",
"label.add-account": "Fiók hozzáadása",
"label.add-website": "Weboldal hozzáadása",
"label.administrator": "Adminisztrátor",
"label.all": "Összes",
"label.all-websites": "Összes weboldal",
"label.all-events": "Összes esemény",
"label.back": "Vissza",
"label.cancel": "Mégsem",
"label.change-password": "Jelszó módosítása",
"label.confirm-password": "Jelszó megerősítése",
"label.copy-to-clipboard": "Vágólapra másolás",
"label.current-password": "Jelenlegi jelszó",
"label.custom-range": "Egyedi tartomány",
"label.dashboard": "Áttekintés",
"label.date-range": "Időintervallum",
"label.default-date-range": "Alapértelmezett időintervallum",
"label.delete": "Eltávolítás",
"label.delete-account": "Fiók eltávolítása",
"label.delete-website": "Weboldal eltávolítása",
"label.dismiss": "Mellőzés",
"label.domain": "Domain",
"label.edit": "Módosítás",
"label.edit-account": "Fiók módosítása",
"label.edit-website": "Weboldal módosítása",
"label.enable-share-url": "URL-megosztás engedélyezése",
"label.invalid": "Érvénytelen",
"label.invalid-domain": "Érvénytelen domain",
"label.last-days": "Legutóbbi {x} nap",
"label.last-hours": "Legutóbbi {x} óra",
"label.logged-in-as": "Bejelentkezve, mint {username}",
"label.login": "Bejelentkezés",
"label.logout": "Kijelentkezés",
"label.more": "Bővebben",
"label.name": "Név",
"label.new-password": "Új jelszó",
"label.password": "Jelszó",
"label.passwords-dont-match": "A jelszavak nem egyeznek",
"label.profile": "Profil",
"label.realtime": "Valós idejű",
"label.realtime-logs": "Valós idejű napló",
"label.refresh": "Frissítés",
"label.required": "Kötelező",
"label.reset": "Visszaállítás",
"label.save": "Mentés",
"label.settings": "Beállítások",
"label.share-url": "URL megosztása",
"label.single-day": "Egy nap",
"label.this-month": "Ezen hónap",
"label.this-week": "Ezen hét",
"label.this-year": "Ezen év",
"label.timezone": "Időzóna",
"label.today": "Ma",
"label.tracking-code": "Követési kód",
"label.unknown": "Ismeretlen",
"label.username": "Felhasználónév",
"label.view-details": "Részletek",
"label.websites": "Weboldalak",
"message.active-users": "{x} {x, plural, one {látogató} other {latógató}} jelenleg",
"message.confirm-delete": "Biztos, hogy törölni szeretnéd {target} elemet?",
"message.copied": "Kimásolva!",
"message.delete-warning": "Minden társított adat törlésre kerül.",
"message.failure": "Valami baj történt.",
"message.get-share-url": "Megosztási URL kimásolása",
"message.get-tracking-code": "Követési kód kimásolása",
"message.go-to-settings": "Tovább a beállításokhoz",
"message.incorrect-username-password": "Érvénytelen felhasználónév/jelszó.",
"message.log.visitor": "Látógató {country} területéről, {os} {device} eszközön, {browser} böngészőből.",
"message.new-version-available": "Elérhető az umami {version} új verziója!",
"message.no-data-available": "Nincs rendelkezésre álló adat.",
"message.no-websites-configured": "Még nem állítottál be egyetlen weboldalt sem.",
"message.page-not-found": "Oldal nem található.",
"message.powered-by": "Működteti az {name}",
"message.save-success": "Sikeres mentés.",
"message.share-url": "{target} nyilvánosan megosztott URL címe.",
"message.track-stats": "{target} statisztikáinak nyomon követéséhez, helyezd el az alábbi kódot a weboldalad {head} részébe.",
"message.type-delete": "Megerősítéshez írd be az alábbi mezőbe azt, hogy {delete}.",
"metrics.actions": "Műveletek",
"metrics.average-visit-time": "Átlagos látogatási idő",
"metrics.bounce-rate": "Visszafordulási arány",
"metrics.browsers": "Böngészők",
"metrics.countries": "Országok",
"metrics.device.desktop": "Asztali számítógép",
"metrics.device.laptop": "Laptop",
"metrics.device.mobile": "Telefon",
"metrics.device.tablet": "Táblagép",
"metrics.devices": "Eszközök",
"metrics.events": "Események",
"metrics.filter.combined": "Összevont",
"metrics.filter.domain-only": "Csak domain",
"metrics.filter.raw": "Nyers",
"metrics.operating-systems": "Operációs rendszerek",
"metrics.page-views": "Oldalmegtekintések",
"metrics.pages": "Oldalak",
"metrics.referrers": "Hivatkozók",
"metrics.unique-visitors": "Egyedi látogatók",
"metrics.views": "Megtekintések",
"metrics.visitors": "Látogatók"
}

View File

@ -57,29 +57,29 @@
"label.view-details": "查看更多",
"label.websites": "網站",
"message.active-users": "当前線上 {x} 人",
"message.confirm-delete": "你確定要删除{target}嗎?",
"message.copied": "複製成功!",
"message.delete-warning": "所有相關數據將會被删除.",
"message.failure": "出現錯誤.",
"message.confirm-delete": "你確定要删除 {target} 嗎?",
"message.copied": "複製成功",
"message.delete-warning": "所有相關數據將會被删除",
"message.failure": "出現錯誤",
"message.get-share-url": "獲得分享連結",
"message.get-tracking-code": "獲得追蹤代碼",
"message.go-to-settings": "去設定",
"message.incorrect-username-password": "用户名或密碼不正確.",
"message.log.visitor": "自 {country} 的訪客在搭載 {os} 的 {device} 上使用 {browser} 進行訪問.",
"message.incorrect-username-password": "用户名或密碼不正確",
"message.log.visitor": "自 {country} 的訪客在搭載 {os} 的 {device} 上使用 {browser} 進行訪問",
"message.new-version-available": "umami 有新版本 {version} 發佈啦!",
"message.no-data-available": "無可用數據.",
"message.no-websites-configured": "目前無任何網站設定.",
"message.page-not-found": "網頁未找到.",
"message.no-data-available": "無可用數據",
"message.no-websites-configured": "目前無任何網站設定",
"message.page-not-found": "網頁未找到",
"message.powered-by": "運行 {name}",
"message.save-success": "成功保存.",
"message.share-url": "這是 {target} 的分享連結.",
"message.track-stats": "將以下代碼放入被設定網站的{head}部分来收集{target}的資料.",
"message.type-delete": "在下方空格輸入{delete}確認",
"message.save-success": "成功保存",
"message.share-url": "這是 {target} 的分享連結",
"message.track-stats": "將以下代碼放入被設定網站的 {head} 部分来收集 {target} 的資料。",
"message.type-delete": "在下方空格輸入 {delete} 確認",
"metrics.actions": "用戶行為",
"metrics.average-visit-time": "平均訪問時間",
"metrics.bounce-rate": "跳出率",
"metrics.browsers": "瀏覽器",
"metrics.countries": "國家",
"metrics.countries": "國家/地區",
"metrics.device.desktop": "桌機",
"metrics.device.laptop": "筆記本",
"metrics.device.mobile": "手機",
@ -94,6 +94,6 @@
"metrics.pages": "網頁",
"metrics.referrers": "指入域名",
"metrics.unique-visitors": "獨立訪客",
"metrics.views": "面流量",
"metrics.views": "面流量",
"metrics.visitors": "獨立訪客"
}

View File

@ -31,75 +31,44 @@ import {
zhCN,
zhTW,
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';
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,
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'];
@ -138,40 +107,5 @@ export const dateLocales = {
'fa-IR': faIR,
'ms-MY': ms,
'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: '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' },
];

View File

@ -10,9 +10,7 @@ module.exports = {
webpack(config) {
config.module.rules.push({
test: /\.svg$/,
issuer: {
test: /\.js$/,
},
issuer: /\.js$/,
use: ['@svgr/webpack'],
});

View File

@ -1,6 +1,6 @@
{
"name": "umami",
"version": "1.18.0",
"version": "1.19.0",
"description": "A simple, fast, website analytics alternative to Google Analytics. ",
"author": "Mike Cao <mike@mikecao.com>",
"license": "MIT",
@ -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",
@ -56,11 +56,11 @@
}
},
"dependencies": {
"@fontsource/inter": "^4.3.0",
"@fontsource/noto-sans-jp": "^4.3.0",
"@fontsource/noto-sans-sc": "^4.3.0",
"@fontsource/noto-sans-tc": "^4.3.0",
"@prisma/client": "2.23.0",
"@fontsource/inter": "^4.5.0",
"@fontsource/noto-sans-jp": "^4.5.0",
"@fontsource/noto-sans-sc": "^4.5.0",
"@fontsource/noto-sans-tc": "^4.5.0",
"@prisma/client": "2.26.0",
"@reduxjs/toolkit": "^1.5.1",
"bcryptjs": "^2.4.3",
"chalk": "^4.1.1",
@ -68,28 +68,28 @@
"classnames": "^2.3.1",
"cookie": "^0.4.1",
"cors": "^2.8.5",
"date-fns": "^2.21.3",
"date-fns-tz": "^1.0.12",
"date-fns": "^2.22.1",
"date-fns-tz": "^1.1.4",
"detect-browser": "^5.2.0",
"dotenv": "^8.2.0",
"formik": "^2.2.7",
"immer": "^9.0.2",
"ipaddr.js": "^2.0.0",
"formik": "^2.2.9",
"immer": "^9.0.5",
"ipaddr.js": "^2.0.1",
"is-localhost-ip": "^1.4.0",
"isbot": "^3.0.26",
"isbot": "^3.1.0",
"jose": "2.0.5",
"maxmind": "^4.3.1",
"maxmind": "^4.3.2",
"moment-timezone": "^0.5.33",
"next": "^10.2.2",
"next": "^11.0.1",
"prompts": "2.4.1",
"prop-types": "^15.7.2",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-intl": "^5.16.0",
"react-intl": "^5.20.4",
"react-redux": "^7.2.4",
"react-simple-maps": "^2.3.0",
"react-spring": "^8.0.27",
"react-tooltip": "^4.2.19",
"react-tooltip": "^4.2.21",
"react-use-measure": "^2.0.4",
"react-window": "^1.8.6",
"redux": "^4.1.0",
@ -102,7 +102,7 @@
"uuid": "^8.3.2"
},
"devDependencies": {
"@formatjs/cli": "^4.2.15",
"@formatjs/cli": "^4.2.27",
"@rollup/plugin-buble": "^0.21.3",
"@rollup/plugin-node-resolve": "^11.2.1",
"@rollup/plugin-replace": "^2.3.4",
@ -110,10 +110,11 @@
"cross-env": "^7.0.3",
"del": "^6.0.0",
"dotenv-cli": "^4.0.0",
"eslint": "^7.26.0",
"eslint": "^7.30.0",
"eslint-config-next": "^11.0.1",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-prettier": "^3.4.0",
"eslint-plugin-react": "^7.23.2",
"eslint-plugin-react": "^7.24.0",
"eslint-plugin-react-hooks": "^4.2.0",
"extract-react-intl-messages": "^4.1.1",
"husky": "^4.3.8",
@ -125,9 +126,9 @@
"postcss-import": "^13.0.0",
"postcss-preset-env": "^6.7.0",
"postcss-rtlcss": "^3.3.2",
"prettier": "^2.3.0",
"prettier": "^2.3.2",
"prettier-eslint": "^12.0.0",
"prisma": "2.23.0",
"prisma": "2.26.0",
"rollup": "^2.48.0",
"rollup-plugin-hashbang": "^2.2.2",
"rollup-plugin-terser": "^7.0.2",

View File

@ -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>;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

1119
yarn.lock

File diff suppressed because it is too large Load Diff