Language switch implemented
This commit is contained in:
@@ -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
47
utils/language.ts
Normal 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 };
|
||||||
|
}
|
||||||
@@ -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"
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user