kopia lustrzana https://github.com/cheeaun/phanpy
Time to migrate away from Lingva
rodzic
de83092259
commit
e586b77a3e
3
.env
3
.env
|
@ -1,4 +1,5 @@
|
||||||
PHANPY_CLIENT_NAME=Phanpy
|
PHANPY_CLIENT_NAME=Phanpy
|
||||||
PHANPY_WEBSITE=https://phanpy.social
|
PHANPY_WEBSITE=https://phanpy.social
|
||||||
PHANPY_LINGVA_INSTANCES="lingva.phanpy.social lingva.lunar.icu lingva.garudalinux.org translate.plausibility.cloud"
|
PHANPY_LINGVA_INSTANCES="lingva.phanpy.social lingva.lunar.icu lingva.garudalinux.org translate.plausibility.cloud"
|
||||||
PHANPY_PRIVACY_POLICY_URL="https://github.com/cheeaun/phanpy/blob/main/PRIVACY.MD"
|
PHANPY_PRIVACY_POLICY_URL="https://github.com/cheeaun/phanpy/blob/main/PRIVACY.MD"
|
||||||
|
PHANPY_TRANSLANG_INSTANCES="translang.phanpy.social"
|
|
@ -238,11 +238,15 @@ Available variables:
|
||||||
- This is applied with the `<meta>` tag on the client-side.
|
- This is applied with the `<meta>` tag on the client-side.
|
||||||
- The policy can also be set with `Referrer-Policy` header configured on the server-side (not this variable).
|
- The policy can also be set with `Referrer-Policy` header configured on the server-side (not this variable).
|
||||||
- Note that since Phanpy uses hash-based URLs, the referrer does not include the hash part.
|
- Note that since Phanpy uses hash-based URLs, the referrer does not include the hash part.
|
||||||
- `PHANPY_LINGVA_INSTANCES` (optional, space-separated list, default: `lingva.phanpy.social [...hard-coded list of fallback instances]`):
|
- `PHANPY_LINGVA_INSTANCES` (**DEPRECATED**, optional, space-separated list, default: `lingva.phanpy.social [...hard-coded list of fallback instances]`):
|
||||||
- Specify a space-separated list of instances. First will be used as default before falling back to the subsequent instances. If there's only 1 instance, means no fallback.
|
- Specify a space-separated list of instances. First will be used as default before falling back to the subsequent instances. If there's only 1 instance, means no fallback.
|
||||||
- May specify a self-hosted Lingva instance, powered by either [lingva-translate](https://github.com/thedaviddelta/lingva-translate) or [lingva-api](https://github.com/cheeaun/lingva-api)
|
- May specify a self-hosted Lingva instance, powered by either [lingva-translate](https://github.com/thedaviddelta/lingva-translate) or [lingva-api](https://github.com/cheeaun/lingva-api)
|
||||||
- List of fallback instances hard-coded in `/.env`
|
- List of fallback instances hard-coded in `/.env`
|
||||||
- [↗️ List of lingva-translate instances](https://github.com/thedaviddelta/lingva-translate?tab=readme-ov-file#instances)
|
- [↗️ List of lingva-translate instances](https://github.com/thedaviddelta/lingva-translate?tab=readme-ov-file#instances)
|
||||||
|
- `PHANPY_TRANSLANG_INSTANCES` (optional, space-separated list, default: `translang.phanpy.social`):
|
||||||
|
- Specify a space-separated list of instances. First will be used as default before falling back to the subsequent instances. If there's only 1 instance, means no fallback.
|
||||||
|
- May specify a self-hosted Translating instance, powered by [translang-api](https://github.com/cheeaun/translang-api).
|
||||||
|
- List of instances hard-coded in `/.env`
|
||||||
- `PHANPY_IMG_ALT_API_URL` (optional, no defaults):
|
- `PHANPY_IMG_ALT_API_URL` (optional, no defaults):
|
||||||
- API endpoint for self-hosted instance of [img-alt-api](https://github.com/cheeaun/img-alt-api).
|
- API endpoint for self-hosted instance of [img-alt-api](https://github.com/cheeaun/img-alt-api).
|
||||||
- If provided, a setting will appear for users to enable the image description generator in the composer. Disabled by default.
|
- If provided, a setting will appear for users to enable the image description generator in the composer. Disabled by default.
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
import fs from 'fs';
|
||||||
|
|
||||||
|
fetch('https://translang.phanpy.social/api/v1/languages')
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then((json) => {
|
||||||
|
const file = './src/data/translang-languages.json';
|
||||||
|
console.log(`Writing ${file}...`);
|
||||||
|
fs.writeFileSync(file, JSON.stringify(json, null, '\t'), 'utf8');
|
||||||
|
});
|
|
@ -119,8 +119,17 @@ function getPollText(poll) {
|
||||||
)
|
)
|
||||||
.join('\n')}`;
|
.join('\n')}`;
|
||||||
}
|
}
|
||||||
function getPostText(status) {
|
function getPostText(status, opts) {
|
||||||
const { spoilerText, content, poll } = status;
|
const { maskCustomEmojis } = opts || {};
|
||||||
|
const { spoilerText, poll, emojis } = status;
|
||||||
|
let { content } = status;
|
||||||
|
if (maskCustomEmojis && emojis?.length) {
|
||||||
|
const emojisRegex = new RegExp(
|
||||||
|
`:(${emojis.map((e) => e.shortcode).join('|')}):`,
|
||||||
|
'g',
|
||||||
|
);
|
||||||
|
content = content.replace(emojisRegex, '⬚');
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
(spoilerText ? `${spoilerText}\n\n` : '') +
|
(spoilerText ? `${spoilerText}\n\n` : '') +
|
||||||
getHTMLText(content) +
|
getHTMLText(content) +
|
||||||
|
@ -139,8 +148,16 @@ function forgivingQSA(selectors = [], dom = document) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
function isTranslateble(content) {
|
function isTranslateble(content, emojis) {
|
||||||
if (!content) return false;
|
if (!content) return false;
|
||||||
|
// Remove custom emojis
|
||||||
|
if (emojis?.length) {
|
||||||
|
const emojisRegex = new RegExp(
|
||||||
|
`:(${emojis.map((e) => e.shortcode).join('|')}):`,
|
||||||
|
'g',
|
||||||
|
);
|
||||||
|
content = content.replace(emojisRegex, '');
|
||||||
|
}
|
||||||
content = content.trim();
|
content = content.trim();
|
||||||
if (!content) return false;
|
if (!content) return false;
|
||||||
const text = getHTMLText(content, {
|
const text = getHTMLText(content, {
|
||||||
|
@ -2212,7 +2229,7 @@ function Status({
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{(((enableTranslate || inlineTranslate) &&
|
{(((enableTranslate || inlineTranslate) &&
|
||||||
isTranslateble(content) &&
|
isTranslateble(content, emojis) &&
|
||||||
differentLanguage) ||
|
differentLanguage) ||
|
||||||
forceTranslate) && (
|
forceTranslate) && (
|
||||||
<TranslationBlock
|
<TranslationBlock
|
||||||
|
@ -2220,7 +2237,9 @@ function Status({
|
||||||
mini={!isSizeLarge && !withinContext}
|
mini={!isSizeLarge && !withinContext}
|
||||||
sourceLanguage={language}
|
sourceLanguage={language}
|
||||||
autoDetected={languageAutoDetected}
|
autoDetected={languageAutoDetected}
|
||||||
text={getPostText(status)}
|
text={getPostText(status, {
|
||||||
|
maskCustomEmojis: true,
|
||||||
|
})}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{!previewMode &&
|
{!previewMode &&
|
||||||
|
|
|
@ -5,7 +5,7 @@ import pRetry from 'p-retry';
|
||||||
import pThrottle from 'p-throttle';
|
import pThrottle from 'p-throttle';
|
||||||
import { useEffect, useRef, useState } from 'preact/hooks';
|
import { useEffect, useRef, useState } from 'preact/hooks';
|
||||||
|
|
||||||
import sourceLanguages from '../data/lingva-source-languages';
|
import languages from '../data/translang-languages';
|
||||||
import {
|
import {
|
||||||
translate as browserTranslate,
|
translate as browserTranslate,
|
||||||
supportsBrowserTranslator,
|
supportsBrowserTranslator,
|
||||||
|
@ -18,9 +18,14 @@ import Icon from './icon';
|
||||||
import LazyShazam from './lazy-shazam';
|
import LazyShazam from './lazy-shazam';
|
||||||
import Loader from './loader';
|
import Loader from './loader';
|
||||||
|
|
||||||
const { PHANPY_LINGVA_INSTANCES } = import.meta.env;
|
const sourceLanguages = Object.entries(languages.sl).map(([code, name]) => ({
|
||||||
const LINGVA_INSTANCES = PHANPY_LINGVA_INSTANCES
|
code,
|
||||||
? PHANPY_LINGVA_INSTANCES.split(/\s+/)
|
name,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const { PHANPY_TRANSLANG_INSTANCES } = import.meta.env;
|
||||||
|
const TRANSLANG_INSTANCES = PHANPY_TRANSLANG_INSTANCES
|
||||||
|
? PHANPY_TRANSLANG_INSTANCES.split(/\s+/)
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
const throttle = pThrottle({
|
const throttle = pThrottle({
|
||||||
|
@ -28,50 +33,70 @@ const throttle = pThrottle({
|
||||||
interval: 2000,
|
interval: 2000,
|
||||||
});
|
});
|
||||||
|
|
||||||
let currentLingvaInstance = 0;
|
const TRANSLATED_MAX_AGE = 1000 * 60 * 60; // 1 hour
|
||||||
|
let currentTranslangInstance = 0;
|
||||||
|
|
||||||
function _lingvaTranslate(text, source, target) {
|
function _translangTranslate(text, source, target) {
|
||||||
console.log('TRANSLATE', text, source, target);
|
console.log('TRANSLATE', text, source, target);
|
||||||
const fetchCall = () => {
|
const fetchCall = () => {
|
||||||
let instance = LINGVA_INSTANCES[currentLingvaInstance];
|
let instance = TRANSLANG_INSTANCES[currentTranslangInstance];
|
||||||
return fetch(
|
const tooLong = text.length > 2000;
|
||||||
`https://${instance}/api/v1/${source}/${target}/${encodeURIComponent(
|
let fetchPromise;
|
||||||
text,
|
if (tooLong) {
|
||||||
)}`,
|
// POST
|
||||||
)
|
fetchPromise = fetch(`https://${instance}/api/v1/translate`, {
|
||||||
|
method: 'POST',
|
||||||
|
priority: 'low',
|
||||||
|
referrerPolicy: 'no-referrer',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
sl: source,
|
||||||
|
tl: target,
|
||||||
|
text,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// GET
|
||||||
|
fetchPromise = fetch(
|
||||||
|
`https://${instance}/api/v1/translate?sl=${encodeURIComponent(source)}&tl=${encodeURIComponent(target)}&text=${encodeURIComponent(text)}`,
|
||||||
|
{
|
||||||
|
priority: 'low',
|
||||||
|
referrerPolicy: 'no-referrer',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return fetchPromise
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
if (!res.ok) throw new Error(res.statusText);
|
if (!res.ok) throw new Error(res.statusText);
|
||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
return {
|
return {
|
||||||
provider: 'lingva',
|
provider: 'translang',
|
||||||
content: res.translation,
|
content: res.translated_text,
|
||||||
detectedSourceLanguage: res.info?.detectedSource,
|
detectedSourceLanguage: res.detected_language,
|
||||||
info: res.info,
|
pronunciation: res.pronunciation,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
return pRetry(fetchCall, {
|
return pRetry(fetchCall, {
|
||||||
retries: 3,
|
retries: 3,
|
||||||
onFailedAttempt: (e) => {
|
onFailedAttempt: (e) => {
|
||||||
currentLingvaInstance =
|
currentTranslangInstance =
|
||||||
(currentLingvaInstance + 1) % LINGVA_INSTANCES.length;
|
(currentTranslangInstance + 1) % TRANSLANG_INSTANCES.length;
|
||||||
console.log(
|
console.log(
|
||||||
'Retrying translation with another instance',
|
'Retrying translation with another instance',
|
||||||
currentLingvaInstance,
|
currentTranslangInstance,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
// return masto.v1.statuses.$select(id).translate({
|
|
||||||
// lang: DEFAULT_LANG,
|
|
||||||
// });
|
|
||||||
}
|
}
|
||||||
const TRANSLATED_MAX_AGE = 1000 * 60 * 60; // 1 hour
|
const translangTranslate = pmem(_translangTranslate, {
|
||||||
const lingvaTranslate = pmem(_lingvaTranslate, {
|
|
||||||
maxAge: TRANSLATED_MAX_AGE,
|
maxAge: TRANSLATED_MAX_AGE,
|
||||||
});
|
});
|
||||||
const throttledLingvaTranslate = pmem(throttle(lingvaTranslate), {
|
const throttledTranslangTranslate = pmem(throttle(translangTranslate), {
|
||||||
// I know, this is double-layered memoization
|
// I know, this is double-layered memoization
|
||||||
maxAge: TRANSLATED_MAX_AGE,
|
maxAge: TRANSLATED_MAX_AGE,
|
||||||
});
|
});
|
||||||
|
@ -99,11 +124,6 @@ function TranslationBlock({
|
||||||
const apiSourceLang = useRef('auto');
|
const apiSourceLang = useRef('auto');
|
||||||
|
|
||||||
if (!onTranslate) {
|
if (!onTranslate) {
|
||||||
// onTranslate = supportsBrowserTranslator
|
|
||||||
// ? browserTranslate
|
|
||||||
// : mini
|
|
||||||
// ? throttledLingvaTranslate
|
|
||||||
// : lingvaTranslate;
|
|
||||||
onTranslate = async (...args) => {
|
onTranslate = async (...args) => {
|
||||||
if (supportsBrowserTranslator) {
|
if (supportsBrowserTranslator) {
|
||||||
const result = await browserTranslate(...args);
|
const result = await browserTranslate(...args);
|
||||||
|
@ -112,8 +132,8 @@ function TranslationBlock({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return mini
|
return mini
|
||||||
? await throttledLingvaTranslate(...args)
|
? await throttledTranslangTranslate(...args)
|
||||||
: await lingvaTranslate(...args);
|
: await translangTranslate(...args);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,8 +147,8 @@ function TranslationBlock({
|
||||||
const detectedLangText = localeCode2Text(detectedSourceLanguage);
|
const detectedLangText = localeCode2Text(detectedSourceLanguage);
|
||||||
setDetectedLang(detectedLangText);
|
setDetectedLang(detectedLangText);
|
||||||
}
|
}
|
||||||
if (provider === 'lingva') {
|
if (provider === 'translang') {
|
||||||
const pronunciation = props?.info?.pronunciation?.query;
|
const pronunciation = props?.pronunciation;
|
||||||
if (pronunciation) {
|
if (pronunciation) {
|
||||||
setPronunciationContent(pronunciation);
|
setPronunciationContent(pronunciation);
|
||||||
}
|
}
|
||||||
|
@ -235,14 +255,14 @@ function TranslationBlock({
|
||||||
code: l.code,
|
code: l.code,
|
||||||
locale: l.code,
|
locale: l.code,
|
||||||
});
|
});
|
||||||
const showCommon = common !== native;
|
const showCommon = native && common !== native;
|
||||||
return (
|
return (
|
||||||
<option value={l.code}>
|
<option value={l.code}>
|
||||||
{l.code === 'auto'
|
{l.code === 'auto'
|
||||||
? t`Auto (${detectedLang ?? '…'})`
|
? t`Auto (${detectedLang ?? '…'})`
|
||||||
: showCommon
|
: showCommon
|
||||||
? `${native} - ${common}`
|
? `${native} - ${common}`
|
||||||
: native}
|
: common}
|
||||||
</option>
|
</option>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
@ -280,4 +300,4 @@ function TranslationBlock({
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default LINGVA_INSTANCES?.length ? TranslationBlock : () => null;
|
export default TRANSLANG_INSTANCES?.length ? TranslationBlock : () => null;
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
[
|
||||||
|
"ca-ES",
|
||||||
|
<<<<<<< HEAD
|
||||||
|
"es-ES",
|
||||||
|
"fi-FI",
|
||||||
|
"gl-ES",
|
||||||
|
"it-IT",
|
||||||
|
"pt-BR",
|
||||||
|
"pt-PT",
|
||||||
|
"zh-CN",
|
||||||
|
"eo-UY",
|
||||||
|
"ru-RU",
|
||||||
|
"eu-ES",
|
||||||
|
"lt-LT",
|
||||||
|
"kab",
|
||||||
|
"de-DE",
|
||||||
|
"uk-UA",
|
||||||
|
"fr-FR",
|
||||||
|
"ko-KR",
|
||||||
|
"cs-CZ",
|
||||||
|
"nl-NL",
|
||||||
|
"fa-IR",
|
||||||
|
"pl-PL"
|
||||||
|
=======
|
||||||
|
"cs-CZ",
|
||||||
|
"de-DE",
|
||||||
|
"eo-UY",
|
||||||
|
"es-ES",
|
||||||
|
"eu-ES",
|
||||||
|
"fa-IR",
|
||||||
|
"fi-FI",
|
||||||
|
"fr-FR",
|
||||||
|
"gl-ES",
|
||||||
|
"it-IT",
|
||||||
|
"kab",
|
||||||
|
"ko-KR",
|
||||||
|
"lt-LT",
|
||||||
|
"nl-NL",
|
||||||
|
"pl-PL",
|
||||||
|
"pt-BR",
|
||||||
|
"pt-PT",
|
||||||
|
"ru-RU",
|
||||||
|
"uk-UA",
|
||||||
|
"zh-CN"
|
||||||
|
>>>>>>> 8eeab341 (Move percentage threshold to build time)
|
||||||
|
]
|
|
@ -0,0 +1,251 @@
|
||||||
|
{
|
||||||
|
"ab": "Аҧсшәа",
|
||||||
|
"ace": "Acèh",
|
||||||
|
"ach": "Lëbacoli",
|
||||||
|
"aa": "Afár",
|
||||||
|
"af": "Afrikaans",
|
||||||
|
"sq": "Shqip",
|
||||||
|
"alz": "Dhalur",
|
||||||
|
"am": "አማርኛ",
|
||||||
|
"ar": "العربية",
|
||||||
|
"hy": "Հայերեն",
|
||||||
|
"as": "অসমীয়া",
|
||||||
|
"av": "Авар мацӀ",
|
||||||
|
"awa": "अवधी",
|
||||||
|
"ay": "Aymar aru",
|
||||||
|
"az": "Azərbaycanca",
|
||||||
|
"ban": "Basa Bali",
|
||||||
|
"bal": "بلوچی",
|
||||||
|
"bm": "Bamanankan",
|
||||||
|
"bci": "Baoulé",
|
||||||
|
"ba": "Башҡортса",
|
||||||
|
"eu": "Euskara",
|
||||||
|
"btx": "Batak Karo",
|
||||||
|
"bts": "Batak Simalungun",
|
||||||
|
"bbc": "Batak Toba",
|
||||||
|
"be": "Беларуская",
|
||||||
|
"bem": "Ichibemba",
|
||||||
|
"bn": "বাংলা",
|
||||||
|
"bew": "Betawi",
|
||||||
|
"bho": "भोजपुरी",
|
||||||
|
"bik": "Bikol",
|
||||||
|
"bs": "Bosanski",
|
||||||
|
"br": "Brezhoneg",
|
||||||
|
"bg": "Български",
|
||||||
|
"bua": "Буряад",
|
||||||
|
"yue": "粵語",
|
||||||
|
"ca": "Català",
|
||||||
|
"ceb": "Cebuano",
|
||||||
|
"ch": "Chamoru",
|
||||||
|
"ce": "Нохчийн мотт",
|
||||||
|
"ny": "Chichewa",
|
||||||
|
"zh-CN": "简体中文",
|
||||||
|
"zh-TW": "繁體中文",
|
||||||
|
"chk": "Kapasen Chuuk",
|
||||||
|
"cv": "Чӑвашла",
|
||||||
|
"co": "Corsu",
|
||||||
|
"crh": "Qırımtatarca (Кирилл)",
|
||||||
|
"crh-Latn": "Qırımtatarca (Latin)",
|
||||||
|
"hr": "Hrvatski",
|
||||||
|
"cs": "Čeština",
|
||||||
|
"da": "Dansk",
|
||||||
|
"fa-AF": "درى",
|
||||||
|
"dv": "ދިވެހި",
|
||||||
|
"din": "Thuɔŋjäŋ",
|
||||||
|
"doi": "डोगरी",
|
||||||
|
"dov": "Dombe",
|
||||||
|
"nl": "Nederlands",
|
||||||
|
"dyu": "Jula",
|
||||||
|
"dz": "རྫོང་ཁ",
|
||||||
|
"en": "English",
|
||||||
|
"eo": "Esperanto",
|
||||||
|
"et": "Eesti",
|
||||||
|
"ee": "Eʋegbe",
|
||||||
|
"fo": "Føroyskt",
|
||||||
|
"fj": "Vosa Vakaviti",
|
||||||
|
"tl": "Tagalog",
|
||||||
|
"fi": "Suomi",
|
||||||
|
"fon": "Fon",
|
||||||
|
"fr": "Français",
|
||||||
|
"fr-CA": "Français (Canada)",
|
||||||
|
"fy": "Frysk",
|
||||||
|
"fur": "Furlan",
|
||||||
|
"ff": "Fulfulde",
|
||||||
|
"gaa": "Gã",
|
||||||
|
"gl": "Galego",
|
||||||
|
"ka": "ქართული",
|
||||||
|
"de": "Deutsch",
|
||||||
|
"el": "Ελληνικά",
|
||||||
|
"gn": "Avañe'ẽ",
|
||||||
|
"gu": "ગુજરાતી",
|
||||||
|
"ht": "Kreyòl ayisyen",
|
||||||
|
"cnh": "Hakha Chin",
|
||||||
|
"ha": "Hausa",
|
||||||
|
"haw": "ʻŌlelo Hawaiʻi",
|
||||||
|
"iw": "עברית",
|
||||||
|
"hil": "Hiligaynon",
|
||||||
|
"hi": "हिन्दी",
|
||||||
|
"hmn": "Hmoob",
|
||||||
|
"hu": "Magyar",
|
||||||
|
"hrx": "Hunsrik",
|
||||||
|
"iba": "Iban",
|
||||||
|
"is": "Íslenska",
|
||||||
|
"ig": "Igbo",
|
||||||
|
"ilo": "Iloko",
|
||||||
|
"id": "Bahasa Indonesia",
|
||||||
|
"iu-Latn": "Inuktitut (Latin)",
|
||||||
|
"iu": "ᐃᓄᒃᑎᑐᑦ",
|
||||||
|
"ga": "Gaeilge",
|
||||||
|
"it": "Italiano",
|
||||||
|
"jam": "Patwa",
|
||||||
|
"ja": "日本語",
|
||||||
|
"jw": "Basa Jawa",
|
||||||
|
"kac": "Jinghpaw",
|
||||||
|
"kl": "Kalaallisut",
|
||||||
|
"kn": "ಕನ್ನಡ",
|
||||||
|
"kr": "Kanuri",
|
||||||
|
"pam": "Kapampangan",
|
||||||
|
"kk": "Қазақша",
|
||||||
|
"kha": "Khasi",
|
||||||
|
"km": "ភាសាខ្មែរ",
|
||||||
|
"cgg": "Rukiga",
|
||||||
|
"kg": "Kikongo",
|
||||||
|
"rw": "Kinyarwanda",
|
||||||
|
"ktu": "Kituba",
|
||||||
|
"trp": "Kokborok",
|
||||||
|
"kv": "Коми кыв",
|
||||||
|
"gom": "कोंकणी",
|
||||||
|
"ko": "한국어",
|
||||||
|
"kri": "Krio",
|
||||||
|
"ku": "Kurdî (Kurmancî)",
|
||||||
|
"ckb": "کوردی (سۆرانی)",
|
||||||
|
"ky": "Кыргызча",
|
||||||
|
"lo": "ລາວ",
|
||||||
|
"ltg": "Latgaļu",
|
||||||
|
"la": "Latina",
|
||||||
|
"lv": "Latviešu",
|
||||||
|
"lij": "Ligure",
|
||||||
|
"li": "Limburgs",
|
||||||
|
"ln": "Lingála",
|
||||||
|
"lt": "Lietuvių",
|
||||||
|
"lmo": "Lombard",
|
||||||
|
"lg": "Luganda",
|
||||||
|
"luo": "Dholuo",
|
||||||
|
"lb": "Lëtzebuergesch",
|
||||||
|
"mk": "Македонски",
|
||||||
|
"mad": "Madhurâ",
|
||||||
|
"mai": "मैथिली",
|
||||||
|
"mak": "Makassar",
|
||||||
|
"mg": "Malagasy",
|
||||||
|
"ms": "Bahasa Melayu",
|
||||||
|
"ms-Arab": "بهاس ملايو",
|
||||||
|
"ml": "മലയാളം",
|
||||||
|
"mt": "Malti",
|
||||||
|
"mam": "Mam",
|
||||||
|
"gv": "Gaelg",
|
||||||
|
"mi": "Te Reo Māori",
|
||||||
|
"mr": "मराठी",
|
||||||
|
"mh": "Kajin M̧ajeļ",
|
||||||
|
"mwr": "मारवाड़ी",
|
||||||
|
"mfe": "Kreol Morisien",
|
||||||
|
"chm": "Олык марий",
|
||||||
|
"mni-Mtei": "ꯃꯤꯇꯩꯂꯣꯟ",
|
||||||
|
"min": "Baso Minang",
|
||||||
|
"lus": "Mizo ṭawng",
|
||||||
|
"mn": "Монгол",
|
||||||
|
"my": "မြန်မာစာ",
|
||||||
|
"nhe": "Náhuatl",
|
||||||
|
"ndc-ZW": "Ndau",
|
||||||
|
"nr": "isiNdebele",
|
||||||
|
"new": "नेपाल भाषा",
|
||||||
|
"ne": "नेपाली",
|
||||||
|
"bm-Nkoo": "ߒߞߏ",
|
||||||
|
"no": "Norsk",
|
||||||
|
"nus": "Thok Nath",
|
||||||
|
"oc": "Occitan",
|
||||||
|
"or": "ଓଡ଼ିଆ",
|
||||||
|
"om": "Afaan Oromoo",
|
||||||
|
"os": "Ирон æвзаг",
|
||||||
|
"pag": "Pangasinan",
|
||||||
|
"pap": "Papiamentu",
|
||||||
|
"ps": "پښتو",
|
||||||
|
"fa": "فارسی",
|
||||||
|
"pl": "Polski",
|
||||||
|
"pt": "Português (Brasil)",
|
||||||
|
"pt-PT": "Português (Portugal)",
|
||||||
|
"pa": "ਪੰਜਾਬੀ",
|
||||||
|
"pa-Arab": "پنجابی",
|
||||||
|
"qu": "Runa Simi",
|
||||||
|
"kek": "Qʼeqchiʼ",
|
||||||
|
"rom": "Romani čhib",
|
||||||
|
"ro": "Română",
|
||||||
|
"rn": "Ikirundi",
|
||||||
|
"ru": "Русский",
|
||||||
|
"se": "Davvisámegiella",
|
||||||
|
"sm": "Gagana Samoa",
|
||||||
|
"sg": "Sängö",
|
||||||
|
"sa": "संस्कृतम्",
|
||||||
|
"sat-Latn": "Santali (Latin)",
|
||||||
|
"sat": "ᱥᱟᱱᱛᱟᱲᱤ",
|
||||||
|
"gd": "Gàidhlig",
|
||||||
|
"nso": "Sepedi",
|
||||||
|
"sr": "Српски",
|
||||||
|
"st": "Sesotho",
|
||||||
|
"crs": "Kreol seselwa",
|
||||||
|
"shn": "လိၵ်ႈတႆး",
|
||||||
|
"sn": "chiShona",
|
||||||
|
"scn": "Sicilianu",
|
||||||
|
"szl": "Ślōnskŏ",
|
||||||
|
"sd": "سنڌي",
|
||||||
|
"si": "සිංහල",
|
||||||
|
"sk": "Slovenčina",
|
||||||
|
"sl": "Slovenščina",
|
||||||
|
"so": "Soomaali",
|
||||||
|
"es": "Español",
|
||||||
|
"su": "Basa Sunda",
|
||||||
|
"sus": "Susu",
|
||||||
|
"sw": "Kiswahili",
|
||||||
|
"ss": "siSwati",
|
||||||
|
"sv": "Svenska",
|
||||||
|
"ty": "Reo Tahiti",
|
||||||
|
"tg": "Тоҷикӣ",
|
||||||
|
"ber-Latn": "Tamazight (Latin)",
|
||||||
|
"ber": "ⵜⴰⵎⴰⵣⵉⵖⵜ",
|
||||||
|
"ta": "தமிழ்",
|
||||||
|
"tt": "Татарча",
|
||||||
|
"te": "తెలుగు",
|
||||||
|
"tet": "Tetun",
|
||||||
|
"th": "ไทย",
|
||||||
|
"bo": "བོད་ཡིག",
|
||||||
|
"ti": "ትግርኛ",
|
||||||
|
"tiv": "Tiv",
|
||||||
|
"tpi": "Tok Pisin",
|
||||||
|
"to": "Lea fakatonga",
|
||||||
|
"lua": "Tshiluba",
|
||||||
|
"ts": "Xitsonga",
|
||||||
|
"tn": "Setswana",
|
||||||
|
"tcy": "ತುಳು",
|
||||||
|
"tum": "chiTumbuka",
|
||||||
|
"tr": "Türkçe",
|
||||||
|
"tk": "Türkmençe",
|
||||||
|
"tyv": "Тыва дыл",
|
||||||
|
"ak": "Akankasa",
|
||||||
|
"udm": "Удмурт кыл",
|
||||||
|
"uk": "Українська",
|
||||||
|
"ur": "اردو",
|
||||||
|
"ug": "ئۇيغۇرچە",
|
||||||
|
"uz": "Oʻzbekcha",
|
||||||
|
"ve": "Tshivenḓa",
|
||||||
|
"vec": "Vèneto",
|
||||||
|
"vi": "Tiếng Việt",
|
||||||
|
"war": "Winaray",
|
||||||
|
"cy": "Cymraeg",
|
||||||
|
"wo": "Wolof",
|
||||||
|
"xh": "isiXhosa",
|
||||||
|
"sah": "Саха тыла",
|
||||||
|
"yi": "ייִדיש",
|
||||||
|
"yo": "Yorùbá",
|
||||||
|
"yua": "Màaya T'àan",
|
||||||
|
"zap": "Didxazá",
|
||||||
|
"zu": "isiZulu"
|
||||||
|
}
|
|
@ -0,0 +1,506 @@
|
||||||
|
{
|
||||||
|
"sl": {
|
||||||
|
"auto": "Detect language",
|
||||||
|
"ab": "Abkhaz",
|
||||||
|
"ace": "Acehnese",
|
||||||
|
"ach": "Acholi",
|
||||||
|
"aa": "Afar",
|
||||||
|
"af": "Afrikaans",
|
||||||
|
"sq": "Albanian",
|
||||||
|
"alz": "Alur",
|
||||||
|
"am": "Amharic",
|
||||||
|
"ar": "Arabic",
|
||||||
|
"hy": "Armenian",
|
||||||
|
"as": "Assamese",
|
||||||
|
"av": "Avar",
|
||||||
|
"awa": "Awadhi",
|
||||||
|
"ay": "Aymara",
|
||||||
|
"az": "Azerbaijani",
|
||||||
|
"ban": "Balinese",
|
||||||
|
"bal": "Baluchi",
|
||||||
|
"bm": "Bambara",
|
||||||
|
"bci": "Baoulé",
|
||||||
|
"ba": "Bashkir",
|
||||||
|
"eu": "Basque",
|
||||||
|
"btx": "Batak Karo",
|
||||||
|
"bts": "Batak Simalungun",
|
||||||
|
"bbc": "Batak Toba",
|
||||||
|
"be": "Belarusian",
|
||||||
|
"bem": "Bemba",
|
||||||
|
"bn": "Bengali",
|
||||||
|
"bew": "Betawi",
|
||||||
|
"bho": "Bhojpuri",
|
||||||
|
"bik": "Bikol",
|
||||||
|
"bs": "Bosnian",
|
||||||
|
"br": "Breton",
|
||||||
|
"bg": "Bulgarian",
|
||||||
|
"bua": "Buryat",
|
||||||
|
"yue": "Cantonese",
|
||||||
|
"ca": "Catalan",
|
||||||
|
"ceb": "Cebuano",
|
||||||
|
"ch": "Chamorro",
|
||||||
|
"ce": "Chechen",
|
||||||
|
"ny": "Chichewa",
|
||||||
|
"zh-CN": "Chinese (Simplified)",
|
||||||
|
"zh-TW": "Chinese (Traditional)",
|
||||||
|
"chk": "Chuukese",
|
||||||
|
"cv": "Chuvash",
|
||||||
|
"co": "Corsican",
|
||||||
|
"crh": "Crimean Tatar (Cyrillic)",
|
||||||
|
"crh-Latn": "Crimean Tatar (Latin)",
|
||||||
|
"hr": "Croatian",
|
||||||
|
"cs": "Czech",
|
||||||
|
"da": "Danish",
|
||||||
|
"fa-AF": "Dari",
|
||||||
|
"dv": "Dhivehi",
|
||||||
|
"din": "Dinka",
|
||||||
|
"doi": "Dogri",
|
||||||
|
"dov": "Dombe",
|
||||||
|
"nl": "Dutch",
|
||||||
|
"dyu": "Dyula",
|
||||||
|
"dz": "Dzongkha",
|
||||||
|
"en": "English",
|
||||||
|
"eo": "Esperanto",
|
||||||
|
"et": "Estonian",
|
||||||
|
"ee": "Ewe",
|
||||||
|
"fo": "Faroese",
|
||||||
|
"fj": "Fijian",
|
||||||
|
"tl": "Filipino",
|
||||||
|
"fi": "Finnish",
|
||||||
|
"fon": "Fon",
|
||||||
|
"fr": "French",
|
||||||
|
"fr-CA": "French (Canada)",
|
||||||
|
"fy": "Frisian",
|
||||||
|
"fur": "Friulian",
|
||||||
|
"ff": "Fulani",
|
||||||
|
"gaa": "Ga",
|
||||||
|
"gl": "Galician",
|
||||||
|
"ka": "Georgian",
|
||||||
|
"de": "German",
|
||||||
|
"el": "Greek",
|
||||||
|
"gn": "Guarani",
|
||||||
|
"gu": "Gujarati",
|
||||||
|
"ht": "Haitian Creole",
|
||||||
|
"cnh": "Hakha Chin",
|
||||||
|
"ha": "Hausa",
|
||||||
|
"haw": "Hawaiian",
|
||||||
|
"iw": "Hebrew",
|
||||||
|
"hil": "Hiligaynon",
|
||||||
|
"hi": "Hindi",
|
||||||
|
"hmn": "Hmong",
|
||||||
|
"hu": "Hungarian",
|
||||||
|
"hrx": "Hunsrik",
|
||||||
|
"iba": "Iban",
|
||||||
|
"is": "Icelandic",
|
||||||
|
"ig": "Igbo",
|
||||||
|
"ilo": "Ilocano",
|
||||||
|
"id": "Indonesian",
|
||||||
|
"iu-Latn": "Inuktut (Latin)",
|
||||||
|
"iu": "Inuktut (Syllabics)",
|
||||||
|
"ga": "Irish",
|
||||||
|
"it": "Italian",
|
||||||
|
"jam": "Jamaican Patois",
|
||||||
|
"ja": "Japanese",
|
||||||
|
"jw": "Javanese",
|
||||||
|
"kac": "Jingpo",
|
||||||
|
"kl": "Kalaallisut",
|
||||||
|
"kn": "Kannada",
|
||||||
|
"kr": "Kanuri",
|
||||||
|
"pam": "Kapampangan",
|
||||||
|
"kk": "Kazakh",
|
||||||
|
"kha": "Khasi",
|
||||||
|
"km": "Khmer",
|
||||||
|
"cgg": "Kiga",
|
||||||
|
"kg": "Kikongo",
|
||||||
|
"rw": "Kinyarwanda",
|
||||||
|
"ktu": "Kituba",
|
||||||
|
"trp": "Kokborok",
|
||||||
|
"kv": "Komi",
|
||||||
|
"gom": "Konkani",
|
||||||
|
"ko": "Korean",
|
||||||
|
"kri": "Krio",
|
||||||
|
"ku": "Kurdish (Kurmanji)",
|
||||||
|
"ckb": "Kurdish (Sorani)",
|
||||||
|
"ky": "Kyrgyz",
|
||||||
|
"lo": "Lao",
|
||||||
|
"ltg": "Latgalian",
|
||||||
|
"la": "Latin",
|
||||||
|
"lv": "Latvian",
|
||||||
|
"lij": "Ligurian",
|
||||||
|
"li": "Limburgish",
|
||||||
|
"ln": "Lingala",
|
||||||
|
"lt": "Lithuanian",
|
||||||
|
"lmo": "Lombard",
|
||||||
|
"lg": "Luganda",
|
||||||
|
"luo": "Luo",
|
||||||
|
"lb": "Luxembourgish",
|
||||||
|
"mk": "Macedonian",
|
||||||
|
"mad": "Madurese",
|
||||||
|
"mai": "Maithili",
|
||||||
|
"mak": "Makassar",
|
||||||
|
"mg": "Malagasy",
|
||||||
|
"ms": "Malay",
|
||||||
|
"ms-Arab": "Malay (Jawi)",
|
||||||
|
"ml": "Malayalam",
|
||||||
|
"mt": "Maltese",
|
||||||
|
"mam": "Mam",
|
||||||
|
"gv": "Manx",
|
||||||
|
"mi": "Maori",
|
||||||
|
"mr": "Marathi",
|
||||||
|
"mh": "Marshallese",
|
||||||
|
"mwr": "Marwadi",
|
||||||
|
"mfe": "Mauritian Creole",
|
||||||
|
"chm": "Meadow Mari",
|
||||||
|
"mni-Mtei": "Meiteilon (Manipuri)",
|
||||||
|
"min": "Minang",
|
||||||
|
"lus": "Mizo",
|
||||||
|
"mn": "Mongolian",
|
||||||
|
"my": "Myanmar (Burmese)",
|
||||||
|
"nhe": "Nahuatl (Eastern Huasteca)",
|
||||||
|
"ndc-ZW": "Ndau",
|
||||||
|
"nr": "Ndebele (South)",
|
||||||
|
"new": "Nepalbhasa (Newari)",
|
||||||
|
"ne": "Nepali",
|
||||||
|
"bm-Nkoo": "NKo",
|
||||||
|
"no": "Norwegian",
|
||||||
|
"nus": "Nuer",
|
||||||
|
"oc": "Occitan",
|
||||||
|
"or": "Odia (Oriya)",
|
||||||
|
"om": "Oromo",
|
||||||
|
"os": "Ossetian",
|
||||||
|
"pag": "Pangasinan",
|
||||||
|
"pap": "Papiamento",
|
||||||
|
"ps": "Pashto",
|
||||||
|
"fa": "Persian",
|
||||||
|
"pl": "Polish",
|
||||||
|
"pt": "Portuguese (Brazil)",
|
||||||
|
"pt-PT": "Portuguese (Portugal)",
|
||||||
|
"pa": "Punjabi (Gurmukhi)",
|
||||||
|
"pa-Arab": "Punjabi (Shahmukhi)",
|
||||||
|
"qu": "Quechua",
|
||||||
|
"kek": "Qʼeqchiʼ",
|
||||||
|
"rom": "Romani",
|
||||||
|
"ro": "Romanian",
|
||||||
|
"rn": "Rundi",
|
||||||
|
"ru": "Russian",
|
||||||
|
"se": "Sami (North)",
|
||||||
|
"sm": "Samoan",
|
||||||
|
"sg": "Sango",
|
||||||
|
"sa": "Sanskrit",
|
||||||
|
"sat-Latn": "Santali (Latin)",
|
||||||
|
"sat": "Santali (Ol Chiki)",
|
||||||
|
"gd": "Scots Gaelic",
|
||||||
|
"nso": "Sepedi",
|
||||||
|
"sr": "Serbian",
|
||||||
|
"st": "Sesotho",
|
||||||
|
"crs": "Seychellois Creole",
|
||||||
|
"shn": "Shan",
|
||||||
|
"sn": "Shona",
|
||||||
|
"scn": "Sicilian",
|
||||||
|
"szl": "Silesian",
|
||||||
|
"sd": "Sindhi",
|
||||||
|
"si": "Sinhala",
|
||||||
|
"sk": "Slovak",
|
||||||
|
"sl": "Slovenian",
|
||||||
|
"so": "Somali",
|
||||||
|
"es": "Spanish",
|
||||||
|
"su": "Sundanese",
|
||||||
|
"sus": "Susu",
|
||||||
|
"sw": "Swahili",
|
||||||
|
"ss": "Swati",
|
||||||
|
"sv": "Swedish",
|
||||||
|
"ty": "Tahitian",
|
||||||
|
"tg": "Tajik",
|
||||||
|
"ber-Latn": "Tamazight",
|
||||||
|
"ber": "Tamazight (Tifinagh)",
|
||||||
|
"ta": "Tamil",
|
||||||
|
"tt": "Tatar",
|
||||||
|
"te": "Telugu",
|
||||||
|
"tet": "Tetum",
|
||||||
|
"th": "Thai",
|
||||||
|
"bo": "Tibetan",
|
||||||
|
"ti": "Tigrinya",
|
||||||
|
"tiv": "Tiv",
|
||||||
|
"tpi": "Tok Pisin",
|
||||||
|
"to": "Tongan",
|
||||||
|
"lua": "Tshiluba",
|
||||||
|
"ts": "Tsonga",
|
||||||
|
"tn": "Tswana",
|
||||||
|
"tcy": "Tulu",
|
||||||
|
"tum": "Tumbuka",
|
||||||
|
"tr": "Turkish",
|
||||||
|
"tk": "Turkmen",
|
||||||
|
"tyv": "Tuvan",
|
||||||
|
"ak": "Twi",
|
||||||
|
"udm": "Udmurt",
|
||||||
|
"uk": "Ukrainian",
|
||||||
|
"ur": "Urdu",
|
||||||
|
"ug": "Uyghur",
|
||||||
|
"uz": "Uzbek",
|
||||||
|
"ve": "Venda",
|
||||||
|
"vec": "Venetian",
|
||||||
|
"vi": "Vietnamese",
|
||||||
|
"war": "Waray",
|
||||||
|
"cy": "Welsh",
|
||||||
|
"wo": "Wolof",
|
||||||
|
"xh": "Xhosa",
|
||||||
|
"sah": "Yakut",
|
||||||
|
"yi": "Yiddish",
|
||||||
|
"yo": "Yoruba",
|
||||||
|
"yua": "Yucatec Maya",
|
||||||
|
"zap": "Zapotec",
|
||||||
|
"zu": "Zulu"
|
||||||
|
},
|
||||||
|
"tl": {
|
||||||
|
"ab": "Abkhaz",
|
||||||
|
"ace": "Acehnese",
|
||||||
|
"ach": "Acholi",
|
||||||
|
"aa": "Afar",
|
||||||
|
"af": "Afrikaans",
|
||||||
|
"sq": "Albanian",
|
||||||
|
"alz": "Alur",
|
||||||
|
"am": "Amharic",
|
||||||
|
"ar": "Arabic",
|
||||||
|
"hy": "Armenian",
|
||||||
|
"as": "Assamese",
|
||||||
|
"av": "Avar",
|
||||||
|
"awa": "Awadhi",
|
||||||
|
"ay": "Aymara",
|
||||||
|
"az": "Azerbaijani",
|
||||||
|
"ban": "Balinese",
|
||||||
|
"bal": "Baluchi",
|
||||||
|
"bm": "Bambara",
|
||||||
|
"bci": "Baoulé",
|
||||||
|
"ba": "Bashkir",
|
||||||
|
"eu": "Basque",
|
||||||
|
"btx": "Batak Karo",
|
||||||
|
"bts": "Batak Simalungun",
|
||||||
|
"bbc": "Batak Toba",
|
||||||
|
"be": "Belarusian",
|
||||||
|
"bem": "Bemba",
|
||||||
|
"bn": "Bengali",
|
||||||
|
"bew": "Betawi",
|
||||||
|
"bho": "Bhojpuri",
|
||||||
|
"bik": "Bikol",
|
||||||
|
"bs": "Bosnian",
|
||||||
|
"br": "Breton",
|
||||||
|
"bg": "Bulgarian",
|
||||||
|
"bua": "Buryat",
|
||||||
|
"yue": "Cantonese",
|
||||||
|
"ca": "Catalan",
|
||||||
|
"ceb": "Cebuano",
|
||||||
|
"ch": "Chamorro",
|
||||||
|
"ce": "Chechen",
|
||||||
|
"ny": "Chichewa",
|
||||||
|
"zh-CN": "Chinese (Simplified)",
|
||||||
|
"zh-TW": "Chinese (Traditional)",
|
||||||
|
"chk": "Chuukese",
|
||||||
|
"cv": "Chuvash",
|
||||||
|
"co": "Corsican",
|
||||||
|
"crh": "Crimean Tatar (Cyrillic)",
|
||||||
|
"crh-Latn": "Crimean Tatar (Latin)",
|
||||||
|
"hr": "Croatian",
|
||||||
|
"cs": "Czech",
|
||||||
|
"da": "Danish",
|
||||||
|
"fa-AF": "Dari",
|
||||||
|
"dv": "Dhivehi",
|
||||||
|
"din": "Dinka",
|
||||||
|
"doi": "Dogri",
|
||||||
|
"dov": "Dombe",
|
||||||
|
"nl": "Dutch",
|
||||||
|
"dyu": "Dyula",
|
||||||
|
"dz": "Dzongkha",
|
||||||
|
"en": "English",
|
||||||
|
"eo": "Esperanto",
|
||||||
|
"et": "Estonian",
|
||||||
|
"ee": "Ewe",
|
||||||
|
"fo": "Faroese",
|
||||||
|
"fj": "Fijian",
|
||||||
|
"tl": "Filipino",
|
||||||
|
"fi": "Finnish",
|
||||||
|
"fon": "Fon",
|
||||||
|
"fr": "French",
|
||||||
|
"fr-CA": "French (Canada)",
|
||||||
|
"fy": "Frisian",
|
||||||
|
"fur": "Friulian",
|
||||||
|
"ff": "Fulani",
|
||||||
|
"gaa": "Ga",
|
||||||
|
"gl": "Galician",
|
||||||
|
"ka": "Georgian",
|
||||||
|
"de": "German",
|
||||||
|
"el": "Greek",
|
||||||
|
"gn": "Guarani",
|
||||||
|
"gu": "Gujarati",
|
||||||
|
"ht": "Haitian Creole",
|
||||||
|
"cnh": "Hakha Chin",
|
||||||
|
"ha": "Hausa",
|
||||||
|
"haw": "Hawaiian",
|
||||||
|
"iw": "Hebrew",
|
||||||
|
"hil": "Hiligaynon",
|
||||||
|
"hi": "Hindi",
|
||||||
|
"hmn": "Hmong",
|
||||||
|
"hu": "Hungarian",
|
||||||
|
"hrx": "Hunsrik",
|
||||||
|
"iba": "Iban",
|
||||||
|
"is": "Icelandic",
|
||||||
|
"ig": "Igbo",
|
||||||
|
"ilo": "Ilocano",
|
||||||
|
"id": "Indonesian",
|
||||||
|
"iu-Latn": "Inuktut (Latin)",
|
||||||
|
"iu": "Inuktut (Syllabics)",
|
||||||
|
"ga": "Irish",
|
||||||
|
"it": "Italian",
|
||||||
|
"jam": "Jamaican Patois",
|
||||||
|
"ja": "Japanese",
|
||||||
|
"jw": "Javanese",
|
||||||
|
"kac": "Jingpo",
|
||||||
|
"kl": "Kalaallisut",
|
||||||
|
"kn": "Kannada",
|
||||||
|
"kr": "Kanuri",
|
||||||
|
"pam": "Kapampangan",
|
||||||
|
"kk": "Kazakh",
|
||||||
|
"kha": "Khasi",
|
||||||
|
"km": "Khmer",
|
||||||
|
"cgg": "Kiga",
|
||||||
|
"kg": "Kikongo",
|
||||||
|
"rw": "Kinyarwanda",
|
||||||
|
"ktu": "Kituba",
|
||||||
|
"trp": "Kokborok",
|
||||||
|
"kv": "Komi",
|
||||||
|
"gom": "Konkani",
|
||||||
|
"ko": "Korean",
|
||||||
|
"kri": "Krio",
|
||||||
|
"ku": "Kurdish (Kurmanji)",
|
||||||
|
"ckb": "Kurdish (Sorani)",
|
||||||
|
"ky": "Kyrgyz",
|
||||||
|
"lo": "Lao",
|
||||||
|
"ltg": "Latgalian",
|
||||||
|
"la": "Latin",
|
||||||
|
"lv": "Latvian",
|
||||||
|
"lij": "Ligurian",
|
||||||
|
"li": "Limburgish",
|
||||||
|
"ln": "Lingala",
|
||||||
|
"lt": "Lithuanian",
|
||||||
|
"lmo": "Lombard",
|
||||||
|
"lg": "Luganda",
|
||||||
|
"luo": "Luo",
|
||||||
|
"lb": "Luxembourgish",
|
||||||
|
"mk": "Macedonian",
|
||||||
|
"mad": "Madurese",
|
||||||
|
"mai": "Maithili",
|
||||||
|
"mak": "Makassar",
|
||||||
|
"mg": "Malagasy",
|
||||||
|
"ms": "Malay",
|
||||||
|
"ms-Arab": "Malay (Jawi)",
|
||||||
|
"ml": "Malayalam",
|
||||||
|
"mt": "Maltese",
|
||||||
|
"mam": "Mam",
|
||||||
|
"gv": "Manx",
|
||||||
|
"mi": "Maori",
|
||||||
|
"mr": "Marathi",
|
||||||
|
"mh": "Marshallese",
|
||||||
|
"mwr": "Marwadi",
|
||||||
|
"mfe": "Mauritian Creole",
|
||||||
|
"chm": "Meadow Mari",
|
||||||
|
"mni-Mtei": "Meiteilon (Manipuri)",
|
||||||
|
"min": "Minang",
|
||||||
|
"lus": "Mizo",
|
||||||
|
"mn": "Mongolian",
|
||||||
|
"my": "Myanmar (Burmese)",
|
||||||
|
"nhe": "Nahuatl (Eastern Huasteca)",
|
||||||
|
"ndc-ZW": "Ndau",
|
||||||
|
"nr": "Ndebele (South)",
|
||||||
|
"new": "Nepalbhasa (Newari)",
|
||||||
|
"ne": "Nepali",
|
||||||
|
"bm-Nkoo": "NKo",
|
||||||
|
"no": "Norwegian",
|
||||||
|
"nus": "Nuer",
|
||||||
|
"oc": "Occitan",
|
||||||
|
"or": "Odia (Oriya)",
|
||||||
|
"om": "Oromo",
|
||||||
|
"os": "Ossetian",
|
||||||
|
"pag": "Pangasinan",
|
||||||
|
"pap": "Papiamento",
|
||||||
|
"ps": "Pashto",
|
||||||
|
"fa": "Persian",
|
||||||
|
"pl": "Polish",
|
||||||
|
"pt": "Portuguese (Brazil)",
|
||||||
|
"pt-PT": "Portuguese (Portugal)",
|
||||||
|
"pa": "Punjabi (Gurmukhi)",
|
||||||
|
"pa-Arab": "Punjabi (Shahmukhi)",
|
||||||
|
"qu": "Quechua",
|
||||||
|
"kek": "Qʼeqchiʼ",
|
||||||
|
"rom": "Romani",
|
||||||
|
"ro": "Romanian",
|
||||||
|
"rn": "Rundi",
|
||||||
|
"ru": "Russian",
|
||||||
|
"se": "Sami (North)",
|
||||||
|
"sm": "Samoan",
|
||||||
|
"sg": "Sango",
|
||||||
|
"sa": "Sanskrit",
|
||||||
|
"sat-Latn": "Santali (Latin)",
|
||||||
|
"sat": "Santali (Ol Chiki)",
|
||||||
|
"gd": "Scots Gaelic",
|
||||||
|
"nso": "Sepedi",
|
||||||
|
"sr": "Serbian",
|
||||||
|
"st": "Sesotho",
|
||||||
|
"crs": "Seychellois Creole",
|
||||||
|
"shn": "Shan",
|
||||||
|
"sn": "Shona",
|
||||||
|
"scn": "Sicilian",
|
||||||
|
"szl": "Silesian",
|
||||||
|
"sd": "Sindhi",
|
||||||
|
"si": "Sinhala",
|
||||||
|
"sk": "Slovak",
|
||||||
|
"sl": "Slovenian",
|
||||||
|
"so": "Somali",
|
||||||
|
"es": "Spanish",
|
||||||
|
"su": "Sundanese",
|
||||||
|
"sus": "Susu",
|
||||||
|
"sw": "Swahili",
|
||||||
|
"ss": "Swati",
|
||||||
|
"sv": "Swedish",
|
||||||
|
"ty": "Tahitian",
|
||||||
|
"tg": "Tajik",
|
||||||
|
"ber-Latn": "Tamazight",
|
||||||
|
"ber": "Tamazight (Tifinagh)",
|
||||||
|
"ta": "Tamil",
|
||||||
|
"tt": "Tatar",
|
||||||
|
"te": "Telugu",
|
||||||
|
"tet": "Tetum",
|
||||||
|
"th": "Thai",
|
||||||
|
"bo": "Tibetan",
|
||||||
|
"ti": "Tigrinya",
|
||||||
|
"tiv": "Tiv",
|
||||||
|
"tpi": "Tok Pisin",
|
||||||
|
"to": "Tongan",
|
||||||
|
"lua": "Tshiluba",
|
||||||
|
"ts": "Tsonga",
|
||||||
|
"tn": "Tswana",
|
||||||
|
"tcy": "Tulu",
|
||||||
|
"tum": "Tumbuka",
|
||||||
|
"tr": "Turkish",
|
||||||
|
"tk": "Turkmen",
|
||||||
|
"tyv": "Tuvan",
|
||||||
|
"ak": "Twi",
|
||||||
|
"udm": "Udmurt",
|
||||||
|
"uk": "Ukrainian",
|
||||||
|
"ur": "Urdu",
|
||||||
|
"ug": "Uyghur",
|
||||||
|
"uz": "Uzbek",
|
||||||
|
"ve": "Venda",
|
||||||
|
"vec": "Venetian",
|
||||||
|
"vi": "Vietnamese",
|
||||||
|
"war": "Waray",
|
||||||
|
"cy": "Welsh",
|
||||||
|
"wo": "Wolof",
|
||||||
|
"xh": "Xhosa",
|
||||||
|
"sah": "Yakut",
|
||||||
|
"yi": "Yiddish",
|
||||||
|
"yo": "Yoruba",
|
||||||
|
"yua": "Yucatec Maya",
|
||||||
|
"zap": "Zapotec",
|
||||||
|
"zu": "Zulu"
|
||||||
|
},
|
||||||
|
"al": {}
|
||||||
|
}
|
Plik diff jest za duży
Load Diff
|
@ -10,7 +10,7 @@ import Icon from '../components/icon';
|
||||||
import LangSelector from '../components/lang-selector';
|
import LangSelector from '../components/lang-selector';
|
||||||
import Link from '../components/link';
|
import Link from '../components/link';
|
||||||
import RelativeTime from '../components/relative-time';
|
import RelativeTime from '../components/relative-time';
|
||||||
import targetLanguages from '../data/lingva-target-languages';
|
import languages from '../data/translang-languages';
|
||||||
import { api } from '../utils/api';
|
import { api } from '../utils/api';
|
||||||
import getTranslateTargetLanguage from '../utils/get-translate-target-language';
|
import getTranslateTargetLanguage from '../utils/get-translate-target-language';
|
||||||
import localeCode2Text from '../utils/localeCode2Text';
|
import localeCode2Text from '../utils/localeCode2Text';
|
||||||
|
@ -32,10 +32,18 @@ const TEXT_SIZES = [14, 15, 16, 17, 18, 19, 20];
|
||||||
const {
|
const {
|
||||||
PHANPY_WEBSITE: WEBSITE,
|
PHANPY_WEBSITE: WEBSITE,
|
||||||
PHANPY_PRIVACY_POLICY_URL: PRIVACY_POLICY_URL,
|
PHANPY_PRIVACY_POLICY_URL: PRIVACY_POLICY_URL,
|
||||||
|
PHANPY_TRANSLANG_INSTANCES: TRANSLANG_INSTANCES,
|
||||||
PHANPY_IMG_ALT_API_URL: IMG_ALT_API_URL,
|
PHANPY_IMG_ALT_API_URL: IMG_ALT_API_URL,
|
||||||
PHANPY_GIPHY_API_KEY: GIPHY_API_KEY,
|
PHANPY_GIPHY_API_KEY: GIPHY_API_KEY,
|
||||||
} = import.meta.env;
|
} = import.meta.env;
|
||||||
|
|
||||||
|
const targetLanguages = Object.entries(languages.tl).map(([code, name]) => ({
|
||||||
|
code,
|
||||||
|
name,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const TRANSLATION_API_NAME = 'TransLang API';
|
||||||
|
|
||||||
function Settings({ onClose }) {
|
function Settings({ onClose }) {
|
||||||
const { t } = useLingui();
|
const { t } = useLingui();
|
||||||
const snapStates = useSnapshot(states);
|
const snapStates = useSnapshot(states);
|
||||||
|
@ -363,46 +371,77 @@ function Settings({ onClose }) {
|
||||||
<Trans>Boosts carousel</Trans>
|
<Trans>Boosts carousel</Trans>
|
||||||
</label>
|
</label>
|
||||||
</li>
|
</li>
|
||||||
<li class="block">
|
{!!TRANSLANG_INSTANCES && (
|
||||||
<label>
|
<li class="block">
|
||||||
<input
|
<label>
|
||||||
type="checkbox"
|
<input
|
||||||
checked={snapStates.settings.contentTranslation}
|
type="checkbox"
|
||||||
onChange={(e) => {
|
checked={snapStates.settings.contentTranslation}
|
||||||
const { checked } = e.target;
|
onChange={(e) => {
|
||||||
states.settings.contentTranslation = checked;
|
const { checked } = e.target;
|
||||||
if (!checked) {
|
states.settings.contentTranslation = checked;
|
||||||
states.settings.contentTranslationTargetLanguage = null;
|
if (!checked) {
|
||||||
}
|
states.settings.contentTranslationTargetLanguage = null;
|
||||||
}}
|
}
|
||||||
/>{' '}
|
}}
|
||||||
<Trans>Post translation</Trans>
|
/>{' '}
|
||||||
</label>
|
<Trans>Post translation</Trans>
|
||||||
<div
|
</label>
|
||||||
class={`sub-section ${
|
<div
|
||||||
!snapStates.settings.contentTranslation
|
class={`sub-section ${
|
||||||
? 'more-insignificant'
|
!snapStates.settings.contentTranslation
|
||||||
: ''
|
? 'more-insignificant'
|
||||||
}`}
|
: ''
|
||||||
>
|
}`}
|
||||||
<div>
|
>
|
||||||
<label>
|
<div>
|
||||||
<Trans>Translate to </Trans>{' '}
|
<label>
|
||||||
<select
|
<Trans>Translate to </Trans>{' '}
|
||||||
value={targetLanguage || ''}
|
<select
|
||||||
disabled={!snapStates.settings.contentTranslation}
|
value={targetLanguage || ''}
|
||||||
style={{ width: '10em' }}
|
disabled={!snapStates.settings.contentTranslation}
|
||||||
onChange={(e) => {
|
style={{ width: '10em' }}
|
||||||
states.settings.contentTranslationTargetLanguage =
|
onChange={(e) => {
|
||||||
e.target.value || null;
|
states.settings.contentTranslationTargetLanguage =
|
||||||
}}
|
e.target.value || null;
|
||||||
>
|
}}
|
||||||
<option value="">
|
>
|
||||||
<Trans>
|
<option value="">
|
||||||
System language ({systemTargetLanguageText})
|
<Trans>
|
||||||
</Trans>
|
System language ({systemTargetLanguageText})
|
||||||
</option>
|
</Trans>
|
||||||
<option disabled>──────────</option>
|
</option>
|
||||||
|
<option disabled>──────────</option>
|
||||||
|
{targetLanguages.map((lang) => {
|
||||||
|
const common = localeCode2Text({
|
||||||
|
code: lang.code,
|
||||||
|
fallback: lang.name,
|
||||||
|
});
|
||||||
|
const native = localeCode2Text({
|
||||||
|
code: lang.code,
|
||||||
|
locale: lang.code,
|
||||||
|
});
|
||||||
|
const showCommon = native && common !== native;
|
||||||
|
return (
|
||||||
|
<option value={lang.code}>
|
||||||
|
{showCommon ? `${native} - ${common}` : common}
|
||||||
|
</option>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<hr />
|
||||||
|
<div class="checkbox-fieldset">
|
||||||
|
<Plural
|
||||||
|
value={
|
||||||
|
snapStates.settings.contentTranslationHideLanguages
|
||||||
|
.length
|
||||||
|
}
|
||||||
|
_0={`Hide "Translate" button for:`}
|
||||||
|
other={`Hide "Translate" button for (#):`}
|
||||||
|
/>
|
||||||
|
<div class="checkbox-fields">
|
||||||
{targetLanguages.map((lang) => {
|
{targetLanguages.map((lang) => {
|
||||||
const common = localeCode2Text({
|
const common = localeCode2Text({
|
||||||
code: lang.code,
|
code: lang.code,
|
||||||
|
@ -412,120 +451,86 @@ function Settings({ onClose }) {
|
||||||
code: lang.code,
|
code: lang.code,
|
||||||
locale: lang.code,
|
locale: lang.code,
|
||||||
});
|
});
|
||||||
const showCommon = common !== native;
|
const showCommon = native && common !== native;
|
||||||
return (
|
return (
|
||||||
<option value={lang.code}>
|
<label>
|
||||||
{showCommon ? `${native} - ${common}` : common}
|
<input
|
||||||
</option>
|
type="checkbox"
|
||||||
|
checked={snapStates.settings.contentTranslationHideLanguages.includes(
|
||||||
|
lang.code,
|
||||||
|
)}
|
||||||
|
onChange={(e) => {
|
||||||
|
const { checked } = e.target;
|
||||||
|
if (checked) {
|
||||||
|
states.settings.contentTranslationHideLanguages.push(
|
||||||
|
lang.code,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
states.settings.contentTranslationHideLanguages =
|
||||||
|
snapStates.settings.contentTranslationHideLanguages.filter(
|
||||||
|
(code) => code !== lang.code,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>{' '}
|
||||||
|
{showCommon ? (
|
||||||
|
<span>
|
||||||
|
{native}{' '}
|
||||||
|
<span class="insignificant ib">- {common}</span>
|
||||||
|
</span>
|
||||||
|
) : (
|
||||||
|
common
|
||||||
|
)}
|
||||||
|
</label>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</select>
|
</div>
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<hr />
|
|
||||||
<div class="checkbox-fieldset">
|
|
||||||
<Plural
|
|
||||||
value={
|
|
||||||
snapStates.settings.contentTranslationHideLanguages.length
|
|
||||||
}
|
|
||||||
_0={`Hide "Translate" button for:`}
|
|
||||||
other={`Hide "Translate" button for (#):`}
|
|
||||||
/>
|
|
||||||
<div class="checkbox-fields">
|
|
||||||
{targetLanguages.map((lang) => {
|
|
||||||
const common = localeCode2Text({
|
|
||||||
code: lang.code,
|
|
||||||
fallback: lang.name,
|
|
||||||
});
|
|
||||||
const native = localeCode2Text({
|
|
||||||
code: lang.code,
|
|
||||||
locale: lang.code,
|
|
||||||
});
|
|
||||||
const showCommon = common !== native;
|
|
||||||
return (
|
|
||||||
<label>
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
checked={snapStates.settings.contentTranslationHideLanguages.includes(
|
|
||||||
lang.code,
|
|
||||||
)}
|
|
||||||
onChange={(e) => {
|
|
||||||
const { checked } = e.target;
|
|
||||||
if (checked) {
|
|
||||||
states.settings.contentTranslationHideLanguages.push(
|
|
||||||
lang.code,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
states.settings.contentTranslationHideLanguages =
|
|
||||||
snapStates.settings.contentTranslationHideLanguages.filter(
|
|
||||||
(code) => code !== lang.code,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>{' '}
|
|
||||||
{showCommon ? (
|
|
||||||
<span>
|
|
||||||
{native}{' '}
|
|
||||||
<span class="insignificant">- {common}</span>
|
|
||||||
</span>
|
|
||||||
) : (
|
|
||||||
common
|
|
||||||
)}
|
|
||||||
</label>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<p class="insignificant">
|
|
||||||
<small>
|
|
||||||
<Trans>
|
|
||||||
Note: This feature uses external translation services,
|
|
||||||
powered by{' '}
|
|
||||||
<a
|
|
||||||
href="https://github.com/cheeaun/lingva-api"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener"
|
|
||||||
>
|
|
||||||
Lingva API
|
|
||||||
</a>{' '}
|
|
||||||
&{' '}
|
|
||||||
<a
|
|
||||||
href="https://github.com/thedaviddelta/lingva-translate"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener"
|
|
||||||
>
|
|
||||||
Lingva Translate
|
|
||||||
</a>
|
|
||||||
.
|
|
||||||
</Trans>
|
|
||||||
</small>
|
|
||||||
</p>
|
|
||||||
<hr />
|
|
||||||
<div>
|
|
||||||
<label>
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
checked={snapStates.settings.contentTranslationAutoInline}
|
|
||||||
disabled={!snapStates.settings.contentTranslation}
|
|
||||||
onChange={(e) => {
|
|
||||||
states.settings.contentTranslationAutoInline =
|
|
||||||
e.target.checked;
|
|
||||||
}}
|
|
||||||
/>{' '}
|
|
||||||
<Trans>Auto inline translation</Trans>
|
|
||||||
</label>
|
|
||||||
<p class="insignificant">
|
<p class="insignificant">
|
||||||
<small>
|
<small>
|
||||||
<Trans>
|
<Trans>
|
||||||
Automatically show translation for posts in timeline.
|
Note: This feature uses external translation services,
|
||||||
Only works for <b>short</b> posts without content
|
powered by{' '}
|
||||||
warning, media and poll.
|
<a
|
||||||
|
href="https://github.com/cheeaun/translang-api"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener"
|
||||||
|
>
|
||||||
|
{TRANSLATION_API_NAME}
|
||||||
|
</a>
|
||||||
|
.
|
||||||
</Trans>
|
</Trans>
|
||||||
</small>
|
</small>
|
||||||
</p>
|
</p>
|
||||||
|
<hr />
|
||||||
|
<div>
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={
|
||||||
|
snapStates.settings.contentTranslationAutoInline
|
||||||
|
}
|
||||||
|
disabled={!snapStates.settings.contentTranslation}
|
||||||
|
onChange={(e) => {
|
||||||
|
states.settings.contentTranslationAutoInline =
|
||||||
|
e.target.checked;
|
||||||
|
}}
|
||||||
|
/>{' '}
|
||||||
|
<Trans>Auto inline translation</Trans>
|
||||||
|
</label>
|
||||||
|
<p class="insignificant">
|
||||||
|
<small>
|
||||||
|
<Trans>
|
||||||
|
Automatically show translation for posts in timeline.
|
||||||
|
Only works for <b>short</b> posts without content
|
||||||
|
warning, media and poll.
|
||||||
|
</Trans>
|
||||||
|
</small>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</li>
|
||||||
</li>
|
)}
|
||||||
{!!GIPHY_API_KEY && authenticated && (
|
{!!GIPHY_API_KEY && authenticated && (
|
||||||
<li class="block">
|
<li class="block">
|
||||||
<label>
|
<label>
|
||||||
|
|
|
@ -1,9 +1,16 @@
|
||||||
import translationTargetLanguages from '../data/lingva-target-languages';
|
import languages from '../data/translang-languages';
|
||||||
|
|
||||||
import localeMatch from './locale-match';
|
import localeMatch from './locale-match';
|
||||||
import mem from './mem';
|
import mem from './mem';
|
||||||
import states from './states';
|
import states from './states';
|
||||||
|
|
||||||
|
const translationTargetLanguages = Object.entries(languages).map(
|
||||||
|
([code, { name }]) => ({
|
||||||
|
code,
|
||||||
|
name,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
const locales = mem(() => [
|
const locales = mem(() => [
|
||||||
new Intl.DateTimeFormat().resolvedOptions().locale,
|
new Intl.DateTimeFormat().resolvedOptions().locale,
|
||||||
...navigator.languages,
|
...navigator.languages,
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
import { i18n } from '@lingui/core';
|
import { i18n } from '@lingui/core';
|
||||||
|
|
||||||
|
import translangLanguagesNative from '../data/translang-languages-native';
|
||||||
|
|
||||||
import mem from './mem';
|
import mem from './mem';
|
||||||
|
|
||||||
// Some codes are not supported by Intl.DisplayNames
|
// Some codes are not supported by Intl.DisplayNames
|
||||||
|
@ -28,6 +30,8 @@ function _localeCode2Text(code) {
|
||||||
if (!fallback) {
|
if (!fallback) {
|
||||||
const anotherText = IntlDN(code).of(code);
|
const anotherText = IntlDN(code).of(code);
|
||||||
if (anotherText !== code) return anotherText;
|
if (anotherText !== code) return anotherText;
|
||||||
|
const yetAnotherText = translangLanguagesNative?.[locale];
|
||||||
|
if (yetAnotherText !== code) return yetAnotherText;
|
||||||
}
|
}
|
||||||
return fallback || '';
|
return fallback || '';
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
Ładowanie…
Reference in New Issue