Add localization for hard-coded English strings
* Replace "Surah X, Ayah Y" with its Arabic equivalenets. * Add support for Eastern Arabic Numerals . For use with the Arabic, and Farsi languages.
This commit is contained in:
parent
112f0aaec7
commit
f1fd6c4e00
6 changed files with 105 additions and 26 deletions
|
@ -1,19 +1,27 @@
|
|||
import { Surah, Ayat, Ayah } from "lib/Quran";
|
||||
import { Surah, Ayat, Ayah, Locale } from "lib/Quran";
|
||||
import React, { useEffect } from "react";
|
||||
import { numbers, strings } from "lib/i18n";
|
||||
import classNames from "classnames";
|
||||
|
||||
interface StreamProps {
|
||||
surah: Surah;
|
||||
stream: Ayat;
|
||||
locale: Locale;
|
||||
}
|
||||
|
||||
export function Stream({ surah, stream }: StreamProps) {
|
||||
export function Stream({ surah, stream, locale }: StreamProps) {
|
||||
const n = numbers(locale);
|
||||
const s = strings(locale);
|
||||
const endOfStream = stream.length === surah.ayat.length;
|
||||
const ayat = stream.map((ayah: Ayah) => {
|
||||
return (
|
||||
<li key={ayah.id} className="ayah fade">
|
||||
<li key={ayah.id.number} className="ayah fade">
|
||||
<span className="surah-id ayah-id">
|
||||
Surah {surah.id}, Ayah {ayah.id}
|
||||
{s("surah")}{" "}
|
||||
{n(surah.id.localeKey)}
|
||||
{s("comma")}{" "}
|
||||
{s("ayah")}{" "}
|
||||
{n(ayah.id.localeKey)}
|
||||
</span>
|
||||
<p>{ayah.text}</p>
|
||||
</li>
|
||||
|
|
|
@ -1,28 +1,30 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import { Surah, Ayah, Ayat } from 'lib/Quran';
|
||||
import { Surah, Ayah, Ayat, Locale } from 'lib/Quran';
|
||||
import { numberToDecimal } from "lib/i18n";
|
||||
|
||||
interface TimerProps {
|
||||
surah: Surah
|
||||
ayah: Ayah
|
||||
locale: Locale
|
||||
stream: Ayat
|
||||
setStream: (stream: Ayat) => void
|
||||
}
|
||||
|
||||
export function Timer ({ surah, ayah, stream, setStream }: TimerProps) {
|
||||
export function Timer ({ surah, ayah, stream, setStream, locale }: TimerProps) {
|
||||
const [ms, setMs] = useState(ayah.readTimeMs);
|
||||
useEffect(() => setMs(ayah.readTimeMs), [ayah]);
|
||||
useEffect(() => {
|
||||
if (stream.length === surah.ayat.length) {
|
||||
return;
|
||||
} else if (ms <= 0) {
|
||||
setStream([...stream, surah.ayat[ayah.id]]);
|
||||
setStream([...stream, surah.ayat[ayah.id.number]]);
|
||||
} else {
|
||||
setTimeout(() => setMs(ms - 100), 100);
|
||||
}
|
||||
}, [ms]);
|
||||
return (
|
||||
<div className='timer'>
|
||||
{(ms / 1000).toFixed(1)}
|
||||
{numberToDecimal(ms / 1000, locale)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import { Surah, Ayah, Ayat } from './Quran/Surah';
|
||||
const Quran = {
|
||||
Surah
|
||||
};
|
||||
export { Quran, Surah, Ayah, Ayat };
|
||||
type Locale = "ar" | "en";
|
||||
const Quran = { Surah };
|
||||
export { Quran, Surah, Ayah, Ayat, Locale };
|
||||
|
|
|
@ -9,13 +9,18 @@ interface SurahDetails {
|
|||
}
|
||||
|
||||
export interface Ayah {
|
||||
id: number;
|
||||
id: IDObject,
|
||||
text: string;
|
||||
readTimeMs: number;
|
||||
}
|
||||
|
||||
export type Ayat = Ayah[];
|
||||
|
||||
interface IDObject {
|
||||
number: number,
|
||||
localeKey: string[]
|
||||
}
|
||||
|
||||
export class Surah {
|
||||
#details: SurahDetails;
|
||||
ayat: Ayat;
|
||||
|
@ -25,7 +30,10 @@ export class Surah {
|
|||
details,
|
||||
ayat.map(([id, text]) => {
|
||||
return {
|
||||
id,
|
||||
id: {
|
||||
number: id,
|
||||
localeKey: String(id).split("")
|
||||
},
|
||||
text,
|
||||
readTimeMs: text.split(" ").length * 500,
|
||||
};
|
||||
|
@ -38,8 +46,11 @@ export class Surah {
|
|||
this.ayat = ayat;
|
||||
}
|
||||
|
||||
get id() {
|
||||
return this.#details.id;
|
||||
get id(): IDObject {
|
||||
return {
|
||||
number: Number(this.#details.id),
|
||||
localeKey: this.#details.id.split("")
|
||||
};
|
||||
}
|
||||
|
||||
get name() {
|
||||
|
|
56
src/js/lib/i18n.ts
Normal file
56
src/js/lib/i18n.ts
Normal file
|
@ -0,0 +1,56 @@
|
|||
import { Locale } from "lib/Quran";
|
||||
type Digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9";
|
||||
type Strings = "decimal" | "surah" | "ayah" | "comma";
|
||||
|
||||
const nTable: Record<Locale, Record<Digit, string>> = {
|
||||
en: {
|
||||
0: "0", 1: "1", 2: "2",
|
||||
3: "3", 4: "4", 5: "5",
|
||||
6: "6", 7: "7", 8: "8",
|
||||
9: "9"
|
||||
},
|
||||
ar: {
|
||||
0: "\u{0660}", 1: "\u{0661}", 2: "\u{0662}",
|
||||
3: "\u{0663}", 4: "\u{0664}", 5: "\u{0665}",
|
||||
6: "\u{0666}", 7: "\u{0667}", 8: "\u{0668}",
|
||||
9: "\u{0669}"
|
||||
}
|
||||
};
|
||||
|
||||
const sTable: Record<Locale, Record<Strings, string>> = {
|
||||
en: {
|
||||
decimal: ".",
|
||||
surah: "Surah",
|
||||
ayah: "Ayah",
|
||||
comma: ","
|
||||
},
|
||||
ar: {
|
||||
decimal: "\u{066B}",
|
||||
surah: "\u{633}\u{648}\u{631}\u{629}",
|
||||
ayah: "\u{622}\u{64a}\u{629}",
|
||||
comma: "\u{60c}"
|
||||
}
|
||||
};
|
||||
|
||||
export function numbers (locale: Locale) {
|
||||
return function(keys: string | string[]): string {
|
||||
const table = nTable[locale];
|
||||
return [...keys].map((k: Digit) => table[k]).join("");
|
||||
};
|
||||
}
|
||||
|
||||
export function strings (locale: Locale) {
|
||||
return function(key: Strings): string {
|
||||
const table = sTable[locale];
|
||||
return table[key];
|
||||
};
|
||||
}
|
||||
|
||||
export function numberToDecimal(number: number, locale: Locale): string {
|
||||
const decimal = number.toFixed(1);
|
||||
const s = strings(locale);
|
||||
const n = numbers(locale);
|
||||
return decimal.split(".")
|
||||
.map((num: Digit) => n(num))
|
||||
.join(s("decimal"));
|
||||
}
|
|
@ -1,15 +1,17 @@
|
|||
import React, { useState, useEffect } from "react";
|
||||
import ReactDOM from "react-dom/client";
|
||||
import useSurah from "hooks/useSurah";
|
||||
import classNames from "classnames";
|
||||
import { get as getCookie } from "es-cookie";
|
||||
import { Timer } from "components/TheQuran/Timer";
|
||||
import { Stream } from "components/TheQuran/Stream";
|
||||
import { AboutSurah } from "components/TheQuran/AboutSurah";
|
||||
import { ThemeSelect } from "components/TheQuran/ThemeSelect";
|
||||
import classNames from "classnames";
|
||||
import { get as getCookie } from "es-cookie";
|
||||
import { Locale } from "lib/Quran";
|
||||
import useSurah from "hooks/useSurah";
|
||||
|
||||
|
||||
interface PageProps {
|
||||
locale: string;
|
||||
locale: Locale;
|
||||
surahId: number;
|
||||
}
|
||||
|
||||
|
@ -17,7 +19,7 @@ function TheSurahPage({ locale, surahId }: PageProps) {
|
|||
const { surahIsLoaded, surah } = useSurah(locale, surahId);
|
||||
const [stream, setStream] = useState([]);
|
||||
const [theme, setTheme] = useState(getCookie("theme") || "moon");
|
||||
const streamIsLoaded = !(stream.length === 0);
|
||||
const readyToRender = stream.length > 0;
|
||||
|
||||
useEffect(() => {
|
||||
if (surahIsLoaded) {
|
||||
|
@ -35,21 +37,22 @@ function TheSurahPage({ locale, surahId }: PageProps) {
|
|||
<a href="/" className="flex-image">
|
||||
<div className="image" />
|
||||
</a>
|
||||
{streamIsLoaded && (
|
||||
{readyToRender && (
|
||||
<div className="flex-row">
|
||||
<span />
|
||||
<ThemeSelect theme={theme} setTheme={setTheme} />
|
||||
<span />
|
||||
</div>
|
||||
)}
|
||||
{streamIsLoaded && <AboutSurah locale={locale} surah={surah} />}
|
||||
{streamIsLoaded && <Stream surah={surah} stream={stream} />}
|
||||
{streamIsLoaded && stream.length < surah.numberOfAyah && (
|
||||
{readyToRender && <AboutSurah locale={locale} surah={surah}/>}
|
||||
{readyToRender && <Stream surah={surah} stream={stream} locale={locale}/>}
|
||||
{readyToRender && stream.length < surah.numberOfAyah && (
|
||||
<Timer
|
||||
surah={surah}
|
||||
ayah={surah.ayat[stream.length - 1]}
|
||||
setStream={setStream}
|
||||
stream={stream}
|
||||
locale={locale}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
@ -57,7 +60,7 @@ function TheSurahPage({ locale, surahId }: PageProps) {
|
|||
}
|
||||
|
||||
const el = document.querySelector(".surah");
|
||||
const locale = el.getAttribute("data-locale");
|
||||
const locale = el.getAttribute("data-locale") as Locale;
|
||||
const surahId = parseInt(el.getAttribute("data-surah-id"));
|
||||
const root = ReactDOM.createRoot(el);
|
||||
root.render(<TheSurahPage locale={locale} surahId={surahId} />);
|
||||
|
|
Loading…
Reference in a new issue