Language switch implemented

This commit is contained in:
David
2021-03-10 21:31:50 +01:00
parent 8f33cb92f2
commit 27ffaa425c
5 changed files with 89 additions and 25 deletions

View File

@@ -4,7 +4,7 @@ import { useRouter } from "next/router";
import Error from "next/error"; import Error from "next/error";
import { googleScrape, extractSlug } from "../utils/translate"; import { googleScrape, extractSlug } from "../utils/translate";
import Languages from "../components/Languages"; import Languages from "../components/Languages";
import { languages, exceptions } from "../utils/languages.json"; import { retrieveFiltered } from "../utils/language";
import langReducer, { Actions, initialState } from "../utils/reducer"; import langReducer, { Actions, initialState } from "../utils/reducer";
const Page: FC<InferGetStaticPropsType<typeof getStaticProps>> = ({ translation, error, initial }) => { const Page: FC<InferGetStaticPropsType<typeof getStaticProps>> = ({ translation, error, initial }) => {
@@ -43,12 +43,15 @@ const Page: FC<InferGetStaticPropsType<typeof getStaticProps>> = ({ translation,
useEffect(updateTranslation, [source, target]); useEffect(updateTranslation, [source, target]);
const langs = Object.entries(languages); const { sourceLangs, targetLangs } = retrieveFiltered(source, target);
const sourceLangs = langs.filter(([code]) => !exceptions.source.includes(code));
const targetLangs = langs.filter(([code]) => !exceptions.target.includes(code));
return ( return (
<div> <div>
<div>
<button onClick={() => dispatch({ type: Actions.SWITCH_LANGS })} disabled={source === "auto"}>
Switch languages
</button>
</div>
<div> <div>
<label htmlFor="source"> <label htmlFor="source">
Source: Source:

47
utils/language.ts Normal file
View File

@@ -0,0 +1,47 @@
import { languages, exceptions, mappings } from "./languages.json";
const checkTypes = {
exception: exceptions,
mapping: mappings
}
type CheckType = keyof typeof checkTypes;
export const langTypes = [
"source",
"target"
] as const;
type LangType = typeof langTypes[number];
const isKeyOf = <T extends object>(obj: T) => (key: keyof any): key is keyof T => key in obj;
export function replaceBoth(
checkType: CheckType,
langs: {
[key in LangType]: string
}
): {
[key in LangType]: string
} {
const [source, target] = langTypes.map(langType => {
const object = checkTypes[checkType][langType];
const langCode = langs[langType];
return isKeyOf(object)(langCode) ? object[langCode] : langCode;
});
return { source, target };
}
export function retrieveFiltered(source: string, target: string) {
const current = {
source: target,
target: source
};
const [sourceLangs, targetLangs] = langTypes.map(type => (
Object.entries(languages).filter(([code]) => (
!Object.keys(exceptions[type]).includes(code)
&& current[type] !== code
))
));
return { sourceLangs, targetLangs };
}

View File

@@ -112,14 +112,15 @@
"zu": "Zulu" "zu": "Zulu"
}, },
"exceptions": { "exceptions": {
"source": [ "source": {
"zh_HANT" "zh_HANT": "zh"
], },
"target": [ "target": {
"auto" "auto": "en"
] }
}, },
"mappings": { "mappings": {
"source": {},
"target": { "target": {
"zh": "zh-CN", "zh": "zh-CN",
"zh_HANT": "zh-TW" "zh_HANT": "zh-TW"

View File

@@ -1,7 +1,4 @@
export enum Actions { import { replaceBoth } from "./language";
"SET_FIELD",
"SET_ALL"
}
export const initialState = { export const initialState = {
source: "auto", source: "auto",
@@ -9,6 +6,14 @@ export const initialState = {
query: "" query: ""
} }
type State = typeof initialState;
export enum Actions {
SET_FIELD,
SET_ALL,
SWITCH_LANGS
}
type Action = { type Action = {
type: Actions.SET_FIELD, type: Actions.SET_FIELD,
payload: { payload: {
@@ -18,19 +23,31 @@ type Action = {
} | { } | {
type: Actions.SET_ALL, type: Actions.SET_ALL,
payload: { payload: {
state: { state: State
[key: string]: string
}
} }
} | {
type: Actions.SWITCH_LANGS
} }
export default function reducer(state: typeof initialState, action: Action) { export default function reducer(state: State, action: Action) {
switch (action.type) { switch (action.type) {
case Actions.SET_FIELD: case Actions.SET_FIELD:
const { key, value } = action.payload; const { key, value } = action.payload;
return { ...state, [key]: value }; return { ...state, [key]: value };
case Actions.SET_ALL: case Actions.SET_ALL:
return { ...state, ...action.payload.state }; return { ...state, ...action.payload.state };
case Actions.SWITCH_LANGS:
const { source, target } = replaceBoth("exception", {
source: state.target,
target: state.source
});
return {
...state,
source: source !== target
? source
: initialState.source,
target
};
default: default:
return state; return state;
} }

View File

@@ -1,7 +1,5 @@
import cheerio from "cheerio"; import cheerio from "cheerio";
import { mappings } from "./languages.json"; import { replaceBoth } from "./language";
const isKeyOf = <T extends object>(obj: T) => (key: keyof any): key is keyof T => key in obj;
export async function googleScrape( export async function googleScrape(
source: string, source: string,
@@ -11,10 +9,8 @@ export async function googleScrape(
translation?: string, translation?: string,
error?: number error?: number
}> { }> {
const newTarget = isKeyOf(mappings.target)(target) const parsed = replaceBoth("mapping", { source, target });
? mappings.target[target] const res = await fetch(`https://translate.google.com/m?sl=${parsed.source}&tl=${parsed.target}&q=${encodeURI(query)}`);
: target;
const res = await fetch(`https://translate.google.com/m?sl=${source}&tl=${newTarget}&q=${encodeURI(query)}`);
if (!res.ok) if (!res.ok)
return { return {