Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: smaller size of locales #39

Merged
merged 1 commit into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions build/plugins/i18n.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import fs from 'node:fs/promises';
import path from 'node:path';

export default (locale) => {
const map = fs
.readFile(
path.resolve(import.meta.dirname, '../../locales/', `${locale}.json`),
{ encoding: 'utf8' },
)
.then(JSON.parse);
return {
resolveId(id) {
if (id.startsWith('at/i18n/')) {
return id;
}
return null;
},
async load(id) {
if (id.startsWith('at/i18n/')) {
const key = id.replace(/at\/i18n\/(.+)/, '$1');
const value = (await map)[key];
if (!value) {
throw new Error('i18n key not found');
}
return `export default ${JSON.stringify(value)}`;
}
},
};
};
8 changes: 2 additions & 6 deletions build/rollup.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import devServer from './plugins/dev-server/index.js';
import generateTemplate from './plugins/generate-template.js';
import i18n from './plugins/i18n.js';
import { readJson, ensureValue } from './utils.js';
import alias from '@rollup/plugin-alias';
import commonjs from '@rollup/plugin-commonjs';
Expand All @@ -13,7 +14,6 @@ import virtual from '@rollup/plugin-virtual';
import { dataToEsm } from '@rollup/pluginutils';
import autoprefixer from 'autoprefixer';
import cssnano from 'cssnano';
import fs from 'node:fs/promises';
import { resolve } from 'node:path';
import postcss from 'rollup-plugin-postcss';
import { swc } from 'rollup-plugin-swc3';
Expand All @@ -30,14 +30,10 @@ export async function rollupOptions(config) {
return {
input: 'entry',
plugins: [
i18n(config.locale),
virtual({
'at/options': dataToEsm(templates[config.id]),
'at/locale': dataToEsm({
map: JSON.parse(
await fs.readFile(`./src/locales/${config.locale}.json`, {
encoding: 'utf-8',
}),
),
locale: config.locale,
}),
entry: buildEntry(),
Expand Down
File renamed without changes.
File renamed without changes.
15 changes: 9 additions & 6 deletions src/components/card-shell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ import {
import { TimerBlock } from './timer';
import { useBack } from '@/hooks/use-back';
import { useField } from '@/hooks/use-field';
import { t } from '@/utils/locale';
import tAbout from 'at/i18n/about';
import tAnswer from 'at/i18n/answer';
import tBack from 'at/i18n/back';
import tTemplateSetting from 'at/i18n/templateSetting';
import { locale } from 'at/locale';
import clsx from 'clsx';
import { useAtomValue } from 'jotai';
Expand Down Expand Up @@ -58,12 +61,12 @@ export const CardShell: FC<Props> = ({
<Block
name={
<div className="flex flex-row justify-between">
<span>{t('templateSetting')}</span>
<span>{tTemplateSetting}</span>
<div
className="cursor-pointer font-bold text-indigo-500"
onClick={() => setShowSettings(false)}
>
{t('back')}
{tBack}
</div>
</div>
}
Expand All @@ -89,7 +92,7 @@ export const CardShell: FC<Props> = ({
className="cursor-pointer font-bold text-indigo-500"
onClick={() => setShowSettings(true)}
>
{t('templateSetting')}
{tTemplateSetting}
</div>
</div>
}
Expand All @@ -103,13 +106,13 @@ export const CardShell: FC<Props> = ({
{questionExtra}
</Block>
{back && answer ? (
<Block name={t('answer')} id={prefNoScroll ? undefined : 'answer'}>
<Block name={tAnswer} id={prefNoScroll ? undefined : 'answer'}>
{answer}
</Block>
) : null}
<TimerBlock />
{prefHideAbout ? null : (
<Block name={t('about')}>
<Block name={tAbout}>
<About />
</Block>
)}
Expand Down
41 changes: 24 additions & 17 deletions src/components/settings.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,18 @@
import { About } from './about';
import { Checkbox } from './checkbox';
import { t } from '@/utils/locale';
import { atomWithLocalStorage } from '@/utils/storage';
import tBiggerText from 'at/i18n/biggerText';
import tBlurOptions from 'at/i18n/blurOptions';
import tBlurOptionsDetail from 'at/i18n/blurOptionsDetail';
import tHideAbout from 'at/i18n/hideAbout';
import tHideQuestionType from 'at/i18n/hideQuestionType';
import tHideQuestionTypeDetail from 'at/i18n/hideQuestionTypeDetail';
import tHideTimer from 'at/i18n/hideTimer';
import tNoScroll from 'at/i18n/noScroll';
import tRandomOption from 'at/i18n/randomOption';
import tRandomOptionDetail from 'at/i18n/randomOptionDetail';
import tSelMenu from 'at/i18n/selMenu';
import tSelMenuDetail from 'at/i18n/selMenuDetail';
import { id } from 'at/options';
import { useAtom } from 'jotai';
import { FC } from 'react';
Expand Down Expand Up @@ -40,28 +51,24 @@ const CommonOptions: FC = () => {
return (
<>
<Checkbox
title={t('biggerText')}
title={tBiggerText}
checked={biggerText}
onChange={setBiggerText}
/>
<Checkbox title={tNoScroll} checked={noScorll} onChange={setNoScorll} />
<Checkbox
title={t('noScroll')}
checked={noScorll}
onChange={setNoScorll}
/>
<Checkbox
title={t('selMenu')}
subtitle={t('selMenuDetail')}
title={tSelMenu}
subtitle={tSelMenuDetail}
checked={selectionMenu}
onChange={setSelectionMenu}
/>
<Checkbox
title={t('hideTimer')}
title={tHideTimer}
checked={hideTimer}
onChange={setHideTimer}
/>
<Checkbox
title={t('hideAbout')}
title={tHideAbout}
checked={hideAbout}
onChange={setHideAbout}
/>
Expand All @@ -82,20 +89,20 @@ if (id === 'mcq') {
return (
<>
<Checkbox
title={t('hideQuestionType')}
title={tHideQuestionType}
checked={hideQuestionType}
onChange={setHideQuestionType}
subtitle={t('hideQuestionTypeDetail')}
subtitle={tHideQuestionTypeDetail}
/>
<Checkbox
title={t('randomOption')}
subtitle={t('randomOptionDetail')}
title={tRandomOption}
subtitle={tRandomOptionDetail}
checked={randomOptions}
onChange={setRandomOptions}
/>
<Checkbox
title={t('blurOptions')}
subtitle={t('blurOptionsDetail')}
title={tBlurOptions}
subtitle={tBlurOptionsDetail}
checked={blurOptions}
onChange={setBlurOptions}
/>
Expand Down
30 changes: 20 additions & 10 deletions src/components/timer.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
import { Block } from './block';
import { Input } from './input';
import { hideTimerAtom } from './settings';
import { t } from '@/utils/locale';
import { atomWithLocalStorage } from '@/utils/storage';
import useCountDown from 'ahooks/es/useCountDown';
import useCreation from 'ahooks/es/useCreation';
import tClose from 'at/i18n/close';
import tDay from 'at/i18n/day';
import tDefaultTimerTitle from 'at/i18n/defaultTimerTitle';
import tHour from 'at/i18n/hour';
import tMinute from 'at/i18n/minute';
import tSecond from 'at/i18n/second';
import tSetting from 'at/i18n/setting';
import tTargetDate from 'at/i18n/targetDate';
import tTimer from 'at/i18n/timer';
import tTimerSetting from 'at/i18n/timerSetting';
import tTimerTitle from 'at/i18n/timerTitle';
import { useAtom, useAtomValue } from 'jotai';
import { FC, useState } from 'react';

Expand All @@ -18,10 +28,10 @@ export const Timer: FC = () => {
const { days, hours, minutes, seconds } = formattedRes;

return [
[t('day'), days],
[t('hour'), hours],
[t('minute'), minutes],
[t('second'), seconds],
[tDay, days],
[tHour, hours],
[tMinute, minutes],
[tSecond, seconds],
];
}, [formattedRes]);

Expand Down Expand Up @@ -52,7 +62,7 @@ interface TimerProps {

const defaultTimerProps = {
targetDate: '2023-12-31',
title: t('defaultTimerTitle'),
title: tDefaultTimerTitle,
};

export const timerAtom = atomWithLocalStorage<TimerProps>(
Expand All @@ -74,20 +84,20 @@ export const TimerBlock = () => {
<Block
name={
<div className="flex flex-row justify-between">
<span>{showSetting ? t('timerSetting') : t('timer')}</span>
<span>{showSetting ? tTimerSetting : tTimer}</span>
<div
className="cursor-pointer font-bold text-indigo-500"
onClick={() => setShowSetting((p) => !p)}
>
{showSetting ? t('close') : t('setting')}
{showSetting ? tClose : tSetting}
</div>
</div>
}
>
{showSetting ? (
<>
<Input
title={t('timerTitle')}
title={tTimerTitle}
value={timer.title}
onChange={(title) =>
setTimer((prevTimer) => ({
Expand All @@ -99,7 +109,7 @@ export const TimerBlock = () => {
/>
<Input
type="date"
title={t('targetDate')}
title={tTargetDate}
value={timer.targetDate || defaultTimerProps.targetDate}
onChange={(targetDate) =>
setTimer((prevTimer) => ({
Expand Down
4 changes: 2 additions & 2 deletions src/entries/basic.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { CardShell } from '../components/card-shell';
import { AnkiField } from '@/components/field';
import { FIELD_ID } from '@/utils/const';
import { isFieldEmpty } from '@/utils/field';
import { t } from '@/utils/locale';
import tQuestion from 'at/i18n/question';
import clsx from 'clsx';

export default () => {
Expand All @@ -11,7 +11,7 @@ export default () => {

return (
<CardShell
title={t('question')}
title={tQuestion}
answer={
hasAnswer || hasNote ? (
<>
Expand Down
29 changes: 21 additions & 8 deletions src/entries/mcq.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {
import { useBack } from '../hooks/use-back';
import { useCrossState } from '../hooks/use-cross-state';
import { useField } from '../hooks/use-field';
import { t } from '../utils/locale';
import { randomOptionsAtom } from '@/components/settings';
import '@/styles/mcq.css';
import { flipToBack } from '@/utils/bridge';
Expand All @@ -18,13 +17,25 @@ import { useAutoAnimate } from '@formkit/auto-animate/preact';
import useCreation from 'ahooks/es/useCreation';
import useMemoizedFn from 'ahooks/es/useMemoizedFn';
import useSelections from 'ahooks/es/useSelections';
import tCorrectAnswer from 'at/i18n/correctAnswer';
import tMissedAnswer from 'at/i18n/missedAnswer';
import tMultipleAnswer from 'at/i18n/multipleAnswer';
import tQuestion from 'at/i18n/question';
import tSingleAnswer from 'at/i18n/singleAnswer';
import tWrongAnswer from 'at/i18n/wrongAnswer';
import { locale } from 'at/locale';
import { fields } from 'at/options';
import clsx from 'clsx';
import { useAtomValue } from 'jotai';
import { useEffect } from 'react';
import { doNothing, shuffle } from 'remeda';

const ANSWER_TYPE_MAP = {
missedAnswer: tMissedAnswer,
correctAnswer: tCorrectAnswer,
wrongAnswer: tWrongAnswer,
};

const fieldToAlpha = (field: string) => field.slice(field.length - 1);

export default () => {
Expand Down Expand Up @@ -111,9 +122,9 @@ export default () => {
<CardShell
title={
prefHideQuestionType || !options.length ? (
t('question')
tQuestion
) : (
<>{isMultipleChoice ? t('multipleAnswer') : t('singleAnswer')}</>
<>{isMultipleChoice ? tMultipleAnswer : tSingleAnswer}</>
)
}
questionExtra={
Expand Down Expand Up @@ -143,11 +154,13 @@ export default () => {
selectResult === 'correct',
'before:text-amber-500 after:bg-amber-500':
selectResult === 'missed',
[`after:content-['${t(
`${
selectResult as Exclude<typeof selectResult, 'none'>
}Answer`,
)}']`]: selectResult !== 'none',
[`after:content-['${
ANSWER_TYPE_MAP[
`${
selectResult as Exclude<typeof selectResult, 'none'>
}Answer`
]
}']`]: selectResult !== 'none',
[clsx(
`before:absolute before:content-['${fieldToAlpha(
name,
Expand Down
7 changes: 4 additions & 3 deletions src/entries/tf.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ import { useCrossState } from '@/hooks/use-cross-state';
import { FIELD_ID } from '@/utils/const';
import { extractTfItems } from '@/utils/extract-tf-items';
import { isFieldEmpty } from '@/utils/field';
import { t } from '@/utils/locale';
import useCreation from 'ahooks/es/useCreation';
import useMemoizedFn from 'ahooks/es/useMemoizedFn';
import tQuestion from 'at/i18n/question';
import tYourWrongAnswer from 'at/i18n/yourWrongAnswer';
import clsx from 'clsx';
import { CheckCircle, XCircle, Triangle } from 'lucide-react';
import { useCallback } from 'react';
Expand Down Expand Up @@ -134,13 +135,13 @@ export default () => {

return (
<CardShell
title={t('question')}
title={tQuestion}
questionExtra={
<>
{items}
{back ? (
<div className="flex items-center justify-end space-x-1 mt-2 text-xs text-gray-500">
{t('yourWrongAnswer')}
{tYourWrongAnswer}
<Triangle
size={12}
fill="#f87171"
Expand Down
Loading
Loading