From c2b52d3db866d9e4ec894910a8cd7ab459a3d82d Mon Sep 17 00:00:00 2001 From: frost768 Date: Thu, 6 Apr 2023 01:46:27 +0300 Subject: [PATCH 1/8] Add language selection --- src/setup/i18n.ts | 18 +- src/setup/iso6391.ts | 1326 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1337 insertions(+), 7 deletions(-) create mode 100644 src/setup/iso6391.ts diff --git a/src/setup/i18n.ts b/src/setup/i18n.ts index d243c0f5..3b18e3f5 100644 --- a/src/setup/i18n.ts +++ b/src/setup/i18n.ts @@ -4,7 +4,13 @@ import LanguageDetector from "i18next-browser-languagedetector"; // Languages import en from "./locales/en/translation.json"; +import { captionLanguages } from "./iso6391"; +const locales = { + en: { + translation: en, + }, +}; i18n // detect user language // learn more: https://github.com/i18next/i18next-browser-languageDetector @@ -15,16 +21,14 @@ i18n // for all options read: https://www.i18next.com/overview/configuration-options .init({ fallbackLng: "en", - - resources: { - en: { - translation: en, - }, - }, - + resources: locales, interpolation: { escapeValue: false, // not needed for react as it escapes by default }, }); +export const appLanguageOptions = captionLanguages.filter((x) => { + return Object.keys(locales).includes(x.id); +}); + export default i18n; diff --git a/src/setup/iso6391.ts b/src/setup/iso6391.ts new file mode 100644 index 00000000..3677560a --- /dev/null +++ b/src/setup/iso6391.ts @@ -0,0 +1,1326 @@ +export type LangCode = + | "none" + | "aa" + | "ab" + | "ae" + | "af" + | "ak" + | "am" + | "an" + | "ar" + | "as" + | "av" + | "ay" + | "az" + | "ba" + | "be" + | "bg" + | "bh" + | "bi" + | "bm" + | "bn" + | "bo" + | "br" + | "bs" + | "ca" + | "ce" + | "ch" + | "co" + | "cr" + | "cs" + | "cu" + | "cv" + | "cy" + | "da" + | "de" + | "dv" + | "dz" + | "ee" + | "el" + | "en" + | "eo" + | "es" + | "et" + | "eu" + | "fa" + | "ff" + | "fi" + | "fj" + | "fo" + | "fr" + | "fy" + | "ga" + | "gd" + | "gl" + | "gn" + | "gu" + | "gv" + | "ha" + | "he" + | "hi" + | "ho" + | "hr" + | "ht" + | "hu" + | "hy" + | "hz" + | "ia" + | "id" + | "ie" + | "ig" + | "ii" + | "ik" + | "io" + | "is" + | "it" + | "iu" + | "ja" + | "jv" + | "ka" + | "kg" + | "ki" + | "kj" + | "kk" + | "kl" + | "km" + | "kn" + | "ko" + | "kr" + | "ks" + | "ku" + | "kv" + | "kw" + | "ky" + | "la" + | "lb" + | "lg" + | "li" + | "ln" + | "lo" + | "lt" + | "lu" + | "lv" + | "mg" + | "mh" + | "mi" + | "mk" + | "ml" + | "mn" + | "mr" + | "ms" + | "mt" + | "my" + | "na" + | "nb" + | "nd" + | "ne" + | "ng" + | "nl" + | "nn" + | "no" + | "nr" + | "nv" + | "ny" + | "oc" + | "oj" + | "om" + | "or" + | "os" + | "pa" + | "pi" + | "pl" + | "ps" + | "pt" + | "qu" + | "rm" + | "rn" + | "ro" + | "ru" + | "rw" + | "sa" + | "sc" + | "sd" + | "se" + | "sg" + | "si" + | "sk" + | "sl" + | "sm" + | "sn" + | "so" + | "sq" + | "sr" + | "ss" + | "st" + | "su" + | "sv" + | "sw" + | "ta" + | "te" + | "tg" + | "th" + | "ti" + | "tk" + | "tl" + | "tn" + | "to" + | "tr" + | "ts" + | "tt" + | "tw" + | "ty" + | "ug" + | "uk" + | "ur" + | "uz" + | "ve" + | "vi" + | "vo" + | "wa" + | "wo" + | "xh" + | "yi" + | "yo" + | "za" + | "zh" + | "zu"; +type CaptionLanguageOptions = { + id: LangCode; + name: string; + englishName: string; + nativeName: string; +}; +// https://github.com/emvi/iso-639-1/blob/master/list.go +// MIT License +// +// Copyright (c) 2019 Emvi +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +export const captionLanguages: CaptionLanguageOptions[] = [ + { + id: "none", + englishName: "None", + name: "None", + nativeName: "None", + }, + { + id: "aa", + englishName: "Afar", + name: "Afar - Afaraf", + nativeName: "Afaraf", + }, + { + id: "ab", + englishName: "Abkhaz", + name: "Abkhaz - Аҧсуа бызшәа", + nativeName: "Аҧсуа бызшәа", + }, + { + id: "ae", + englishName: "Avestan", + name: "Avestan - Avesta", + nativeName: "Avesta", + }, + { + id: "af", + englishName: "Afrikaans", + name: "Afrikaans - Afrikaans", + nativeName: "Afrikaans", + }, + { + id: "ak", + englishName: "Akan", + name: "Akan - Akan", + nativeName: "Akan", + }, + { + id: "am", + englishName: "Amharic", + name: "Amharic - አማርኛ", + nativeName: "አማርኛ", + }, + { + id: "an", + englishName: "Aragonese", + name: "Aragonese - Aragonés", + nativeName: "Aragonés", + }, + { + id: "ar", + englishName: "Arabic", + name: "Arabic - اللغة العربية", + nativeName: "اللغة العربية", + }, + { + id: "as", + englishName: "Assamese", + name: "Assamese - অসমীয়া", + nativeName: "অসমীয়া", + }, + { + id: "av", + englishName: "Avaric", + name: "Avaric - Авар мацӀ", + nativeName: "Авар мацӀ", + }, + { + id: "ay", + englishName: "Aymara", + name: "Aymara - Aymar aru", + nativeName: "Aymar aru", + }, + { + id: "az", + englishName: "Azerbaijani", + name: "Azerbaijani - Azərbaycan dili", + nativeName: "Azərbaycan dili", + }, + { + id: "ba", + englishName: "Bashkir", + name: "Bashkir - Башҡорт теле", + nativeName: "Башҡорт теле", + }, + { + id: "be", + englishName: "Belarusian", + name: "Belarusian - Беларуская мова", + nativeName: "Беларуская мова", + }, + { + id: "bg", + englishName: "Bulgarian", + name: "Bulgarian - Български език", + nativeName: "Български език", + }, + { + id: "bh", + englishName: "Bihari", + name: "Bihari - भोजपुरी", + nativeName: "भोजपुरी", + }, + { + id: "bi", + englishName: "Bislama", + name: "Bislama - Bislama", + nativeName: "Bislama", + }, + { + id: "bm", + englishName: "Bambara", + name: "Bambara - Bamanankan", + nativeName: "Bamanankan", + }, + { + id: "bn", + englishName: "Bengali", + name: "Bengali - বাংলা", + nativeName: "বাংলা", + }, + { + id: "bo", + englishName: "Tibetan Standard", + name: "Tibetan Standard - བོད་ཡིག", + nativeName: "བོད་ཡིག", + }, + { + id: "br", + englishName: "Breton", + name: "Breton - Brezhoneg", + nativeName: "Brezhoneg", + }, + { + id: "bs", + englishName: "Bosnian", + name: "Bosnian - Bosanski jezik", + nativeName: "Bosanski jezik", + }, + { + id: "ca", + englishName: "Catalan", + name: "Catalan - Català", + nativeName: "Català", + }, + { + id: "ce", + englishName: "Chechen", + name: "Chechen - Нохчийн мотт", + nativeName: "Нохчийн мотт", + }, + { + id: "ch", + englishName: "Chamorro", + name: "Chamorro - Chamoru", + nativeName: "Chamoru", + }, + { + id: "co", + englishName: "Corsican", + name: "Corsican - Corsu", + nativeName: "Corsu", + }, + { + id: "cr", + englishName: "Cree", + name: "Cree - ᓀᐦᐃᔭᐍᐏᐣ", + nativeName: "ᓀᐦᐃᔭᐍᐏᐣ", + }, + { + id: "cs", + englishName: "Czech", + name: "Czech - Čeština", + nativeName: "Čeština", + }, + { + id: "cu", + englishName: "Old Church Slavonic", + name: "Old Church Slavonic - Ѩзыкъ словѣньскъ", + nativeName: "Ѩзыкъ словѣньскъ", + }, + { + id: "cv", + englishName: "Chuvash", + name: "Chuvash - Чӑваш чӗлхи", + nativeName: "Чӑваш чӗлхи", + }, + { + id: "cy", + englishName: "Welsh", + name: "Welsh - Cymraeg", + nativeName: "Cymraeg", + }, + { + id: "da", + englishName: "Danish", + name: "Danish - Dansk", + nativeName: "Dansk", + }, + { + id: "de", + englishName: "German", + name: "German - Deutsch", + nativeName: "Deutsch", + }, + { + id: "dv", + englishName: "Divehi", + name: "Divehi - Dhivehi", + nativeName: "Dhivehi", + }, + { + id: "dz", + englishName: "Dzongkha", + name: "Dzongkha - རྫོང་ཁ", + nativeName: "རྫོང་ཁ", + }, + { + id: "ee", + englishName: "Ewe", + name: "Ewe - Eʋegbe", + nativeName: "Eʋegbe", + }, + { + id: "el", + englishName: "Greek", + name: "Greek - Ελληνικά", + nativeName: "Ελληνικά", + }, + { + id: "en", + englishName: "English", + name: "English - English", + nativeName: "English", + }, + { + id: "eo", + englishName: "Esperanto", + name: "Esperanto - Esperanto", + nativeName: "Esperanto", + }, + { + id: "es", + englishName: "Spanish", + name: "Spanish - Español", + nativeName: "Español", + }, + { + id: "et", + englishName: "Estonian", + name: "Estonian - Eesti", + nativeName: "Eesti", + }, + { + id: "eu", + englishName: "Basque", + name: "Basque - Euskara", + nativeName: "Euskara", + }, + { + id: "fa", + englishName: "Persian", + name: "Persian - فارسی", + nativeName: "فارسی", + }, + { + id: "ff", + englishName: "Fula", + name: "Fula - Fulfulde", + nativeName: "Fulfulde", + }, + { + id: "fi", + englishName: "Finnish", + name: "Finnish - Suomi", + nativeName: "Suomi", + }, + { + id: "fj", + englishName: "Fijian", + name: "Fijian - Vakaviti", + nativeName: "Vakaviti", + }, + { + id: "fo", + englishName: "Faroese", + name: "Faroese - Føroyskt", + nativeName: "Føroyskt", + }, + { + id: "fr", + englishName: "French", + name: "French - Français", + nativeName: "Français", + }, + { + id: "fy", + englishName: "Western Frisian", + name: "Western Frisian - Frysk", + nativeName: "Frysk", + }, + { + id: "ga", + englishName: "Irish", + name: "Irish - Gaeilge", + nativeName: "Gaeilge", + }, + { + id: "gd", + englishName: "Scottish Gaelic", + name: "Scottish Gaelic - Gàidhlig", + nativeName: "Gàidhlig", + }, + { + id: "gl", + englishName: "Galician", + name: "Galician - Galego", + nativeName: "Galego", + }, + { + id: "gn", + englishName: "Guaraní", + name: "Guaraní - Avañeẽ", + nativeName: "Avañeẽ", + }, + { + id: "gu", + englishName: "Gujarati", + name: "Gujarati - ગુજરાતી", + nativeName: "ગુજરાતી", + }, + { + id: "gv", + englishName: "Manx", + name: "Manx - Gaelg", + nativeName: "Gaelg", + }, + { + id: "ha", + englishName: "Hausa", + name: "Hausa - هَوُسَ", + nativeName: "هَوُسَ", + }, + { + id: "he", + englishName: "Hebrew", + name: "Hebrew - עברית", + nativeName: "עברית", + }, + { + id: "hi", + englishName: "Hindi", + name: "Hindi - हिन्दी", + nativeName: "हिन्दी", + }, + { + id: "ho", + englishName: "Hiri Motu", + name: "Hiri Motu - Hiri Motu", + nativeName: "Hiri Motu", + }, + { + id: "hr", + englishName: "Croatian", + name: "Croatian - Hrvatski jezik", + nativeName: "Hrvatski jezik", + }, + { + id: "ht", + englishName: "Haitian", + name: "Haitian - Kreyòl ayisyen", + nativeName: "Kreyòl ayisyen", + }, + { + id: "hu", + englishName: "Hungarian", + name: "Hungarian - Magyar", + nativeName: "Magyar", + }, + { + id: "hy", + englishName: "Armenian", + name: "Armenian - Հայերեն", + nativeName: "Հայերեն", + }, + { + id: "hz", + englishName: "Herero", + name: "Herero - Otjiherero", + nativeName: "Otjiherero", + }, + { + id: "ia", + englishName: "Interlingua", + name: "Interlingua - Interlingua", + nativeName: "Interlingua", + }, + { + id: "id", + englishName: "Indonesian", + name: "Indonesian - Indonesian", + nativeName: "Indonesian", + }, + { + id: "ie", + englishName: "Interlingue", + name: "Interlingue - Interlingue", + nativeName: "Interlingue", + }, + { + id: "ig", + englishName: "Igbo", + name: "Igbo - Asụsụ Igbo", + nativeName: "Asụsụ Igbo", + }, + { + id: "ii", + englishName: "Nuosu", + name: "Nuosu - ꆈꌠ꒿ Nuosuhxop", + nativeName: "ꆈꌠ꒿ Nuosuhxop", + }, + { + id: "ik", + englishName: "Inupiaq", + name: "Inupiaq - Iñupiaq", + nativeName: "Iñupiaq", + }, + { + id: "io", + englishName: "Ido", + name: "Ido - Ido", + nativeName: "Ido", + }, + { + id: "is", + englishName: "Icelandic", + name: "Icelandic - Íslenska", + nativeName: "Íslenska", + }, + { + id: "it", + englishName: "Italian", + name: "Italian - Italiano", + nativeName: "Italiano", + }, + { + id: "iu", + englishName: "Inuktitut", + name: "Inuktitut - ᐃᓄᒃᑎᑐᑦ", + nativeName: "ᐃᓄᒃᑎᑐᑦ", + }, + { + id: "ja", + englishName: "Japanese", + name: "Japanese - 日本語", + nativeName: "日本語", + }, + { + id: "jv", + englishName: "Javanese", + name: "Javanese - Basa Jawa", + nativeName: "Basa Jawa", + }, + { + id: "ka", + englishName: "Georgian", + name: "Georgian - Ქართული", + nativeName: "Ქართული", + }, + { + id: "kg", + englishName: "Kongo", + name: "Kongo - Kikongo", + nativeName: "Kikongo", + }, + { + id: "ki", + englishName: "Kikuyu", + name: "Kikuyu - Gĩkũyũ", + nativeName: "Gĩkũyũ", + }, + { + id: "kj", + englishName: "Kwanyama", + name: "Kwanyama - Kuanyama", + nativeName: "Kuanyama", + }, + { + id: "kk", + englishName: "Kazakh", + name: "Kazakh - Қазақ тілі", + nativeName: "Қазақ тілі", + }, + { + id: "kl", + englishName: "Kalaallisut", + name: "Kalaallisut - Kalaallisut", + nativeName: "Kalaallisut", + }, + { + id: "km", + englishName: "Khmer", + name: "Khmer - ខេមរភាសា", + nativeName: "ខេមរភាសា", + }, + { + id: "kn", + englishName: "Kannada", + name: "Kannada - ಕನ್ನಡ", + nativeName: "ಕನ್ನಡ", + }, + { + id: "ko", + englishName: "Korean", + name: "Korean - 한국어", + nativeName: "한국어", + }, + { + id: "kr", + englishName: "Kanuri", + name: "Kanuri - Kanuri", + nativeName: "Kanuri", + }, + { + id: "ks", + englishName: "Kashmiri", + name: "Kashmiri - कश्मीरी", + nativeName: "कश्मीरी", + }, + { + id: "ku", + englishName: "Kurdish", + name: "Kurdish - Kurdî", + nativeName: "Kurdî", + }, + { + id: "kv", + englishName: "Komi", + name: "Komi - Коми кыв", + nativeName: "Коми кыв", + }, + { + id: "kw", + englishName: "Cornish", + name: "Cornish - Kernewek", + nativeName: "Kernewek", + }, + { + id: "ky", + englishName: "Kyrgyz", + name: "Kyrgyz - Кыргызча", + nativeName: "Кыргызча", + }, + { + id: "la", + englishName: "Latin", + name: "Latin - Latine", + nativeName: "Latine", + }, + { + id: "lb", + englishName: "Luxembourgish", + name: "Luxembourgish - Lëtzebuergesch", + nativeName: "Lëtzebuergesch", + }, + { + id: "lg", + englishName: "Ganda", + name: "Ganda - Luganda", + nativeName: "Luganda", + }, + { + id: "li", + englishName: "Limburgish", + name: "Limburgish - Limburgs", + nativeName: "Limburgs", + }, + { + id: "ln", + englishName: "Lingala", + name: "Lingala - Lingála", + nativeName: "Lingála", + }, + { + id: "lo", + englishName: "Lao", + name: "Lao - ພາສາ", + nativeName: "ພາສາ", + }, + { + id: "lt", + englishName: "Lithuanian", + name: "Lithuanian - Lietuvių kalba", + nativeName: "Lietuvių kalba", + }, + { + id: "lu", + englishName: "Luba-Katanga", + name: "Luba-Katanga - Tshiluba", + nativeName: "Tshiluba", + }, + { + id: "lv", + englishName: "Latvian", + name: "Latvian - Latviešu valoda", + nativeName: "Latviešu valoda", + }, + { + id: "mg", + englishName: "Malagasy", + name: "Malagasy - Fiteny malagasy", + nativeName: "Fiteny malagasy", + }, + { + id: "mh", + englishName: "Marshallese", + name: "Marshallese - Kajin M̧ajeļ", + nativeName: "Kajin M̧ajeļ", + }, + { + id: "mi", + englishName: "Māori", + name: "Māori - Te reo Māori", + nativeName: "Te reo Māori", + }, + { + id: "mk", + englishName: "Macedonian", + name: "Macedonian - Македонски јазик", + nativeName: "Македонски јазик", + }, + { + id: "ml", + englishName: "Malayalam", + name: "Malayalam - മലയാളം", + nativeName: "മലയാളം", + }, + { + id: "mn", + englishName: "Mongolian", + name: "Mongolian - Монгол хэл", + nativeName: "Монгол хэл", + }, + { + id: "mr", + englishName: "Marathi", + name: "Marathi - मराठी", + nativeName: "मराठी", + }, + { + id: "ms", + englishName: "Malay", + name: "Malay - هاس ملايو‎", + nativeName: "هاس ملايو‎", + }, + { + id: "mt", + englishName: "Maltese", + name: "Maltese - Malti", + nativeName: "Malti", + }, + { + id: "my", + englishName: "Burmese", + name: "Burmese - ဗမာစာ", + nativeName: "ဗမာစာ", + }, + { + id: "na", + englishName: "Nauru", + name: "Nauru - Ekakairũ Naoero", + nativeName: "Ekakairũ Naoero", + }, + { + id: "nb", + englishName: "Norwegian Bokmål", + name: "Norwegian Bokmål - Norsk bokmål", + nativeName: "Norsk bokmål", + }, + { + id: "nd", + englishName: "Northern Ndebele", + name: "Northern Ndebele - IsiNdebele", + nativeName: "IsiNdebele", + }, + { + id: "ne", + englishName: "Nepali", + name: "Nepali - नेपाली", + nativeName: "नेपाली", + }, + { + id: "ng", + englishName: "Ndonga", + name: "Ndonga - Owambo", + nativeName: "Owambo", + }, + { + id: "nl", + englishName: "Dutch", + name: "Dutch - Nederlands", + nativeName: "Nederlands", + }, + { + id: "nn", + englishName: "Norwegian Nynorsk", + name: "Norwegian Nynorsk - Norsk nynorsk", + nativeName: "Norsk nynorsk", + }, + { + id: "no", + englishName: "Norwegian", + name: "Norwegian - Norsk", + nativeName: "Norsk", + }, + { + id: "nr", + englishName: "Southern Ndebele", + name: "Southern Ndebele - IsiNdebele", + nativeName: "IsiNdebele", + }, + { + id: "nv", + englishName: "Navajo", + name: "Navajo - Diné bizaad", + nativeName: "Diné bizaad", + }, + { + id: "ny", + englishName: "Chichewa", + name: "Chichewa - ChiCheŵa", + nativeName: "ChiCheŵa", + }, + { + id: "oc", + englishName: "Occitan", + name: "Occitan - Occitan", + nativeName: "Occitan", + }, + { + id: "oj", + englishName: "Ojibwe", + name: "Ojibwe - ᐊᓂᔑᓈᐯᒧᐎᓐ", + nativeName: "ᐊᓂᔑᓈᐯᒧᐎᓐ", + }, + { + id: "om", + englishName: "Oromo", + name: "Oromo - Afaan Oromoo", + nativeName: "Afaan Oromoo", + }, + { + id: "or", + englishName: "Oriya", + name: "Oriya - ଓଡ଼ିଆ", + nativeName: "ଓଡ଼ିଆ", + }, + { + id: "os", + englishName: "Ossetian", + name: "Ossetian - Ирон æвзаг", + nativeName: "Ирон æвзаг", + }, + { + id: "pa", + englishName: "Panjabi", + name: "Panjabi - ਪੰਜਾਬੀ", + nativeName: "ਪੰਜਾਬੀ", + }, + { + id: "pi", + englishName: "Pāli", + name: "Pāli - पाऴि", + nativeName: "पाऴि", + }, + { + id: "pl", + englishName: "Polish", + name: "Polish - Język polski", + nativeName: "Język polski", + }, + { + id: "ps", + englishName: "Pashto", + name: "Pashto - پښتو", + nativeName: "پښتو", + }, + { + id: "pt", + englishName: "Portuguese", + name: "Portuguese - Português", + nativeName: "Português", + }, + { + id: "qu", + englishName: "Quechua", + name: "Quechua - Runa Simi", + nativeName: "Runa Simi", + }, + { + id: "rm", + englishName: "Romansh", + name: "Romansh - Rumantsch grischun", + nativeName: "Rumantsch grischun", + }, + { + id: "rn", + englishName: "Kirundi", + name: "Kirundi - Ikirundi", + nativeName: "Ikirundi", + }, + { + id: "ro", + englishName: "Romanian", + name: "Romanian - Română", + nativeName: "Română", + }, + { + id: "ru", + englishName: "Russian", + name: "Russian - Русский", + nativeName: "Русский", + }, + { + id: "rw", + englishName: "Kinyarwanda", + name: "Kinyarwanda - Ikinyarwanda", + nativeName: "Ikinyarwanda", + }, + { + id: "sa", + englishName: "Sanskrit", + name: "Sanskrit - संस्कृतम्", + nativeName: "संस्कृतम्", + }, + { + id: "sc", + englishName: "Sardinian", + name: "Sardinian - Sardu", + nativeName: "Sardu", + }, + { + id: "sd", + englishName: "Sindhi", + name: "Sindhi - सिन्धी", + nativeName: "सिन्धी", + }, + { + id: "se", + englishName: "Northern Sami", + name: "Northern Sami - Davvisámegiella", + nativeName: "Davvisámegiella", + }, + { + id: "sg", + englishName: "Sango", + name: "Sango - Yângâ tî sängö", + nativeName: "Yângâ tî sängö", + }, + { + id: "si", + englishName: "Sinhala", + name: "Sinhala - සිංහල", + nativeName: "සිංහල", + }, + { + id: "sk", + englishName: "Slovak", + name: "Slovak - Slovenčina", + nativeName: "Slovenčina", + }, + { + id: "sl", + englishName: "Slovene", + name: "Slovene - Slovenski jezik", + nativeName: "Slovenski jezik", + }, + { + id: "sm", + englishName: "Samoan", + name: "Samoan - Gagana faa Samoa", + nativeName: "Gagana faa Samoa", + }, + { + id: "sn", + englishName: "Shona", + name: "Shona - ChiShona", + nativeName: "ChiShona", + }, + { + id: "so", + englishName: "Somali", + name: "Somali - Soomaaliga", + nativeName: "Soomaaliga", + }, + { + id: "sq", + englishName: "Albanian", + name: "Albanian - Shqip", + nativeName: "Shqip", + }, + { + id: "sr", + englishName: "Serbian", + name: "Serbian - Српски језик", + nativeName: "Српски језик", + }, + { + id: "ss", + englishName: "Swati", + name: "Swati - SiSwati", + nativeName: "SiSwati", + }, + { + id: "st", + englishName: "Southern Sotho", + name: "Southern Sotho - Sesotho", + nativeName: "Sesotho", + }, + { + id: "su", + englishName: "Sundanese", + name: "Sundanese - Basa Sunda", + nativeName: "Basa Sunda", + }, + { + id: "sv", + englishName: "Swedish", + name: "Swedish - Svenska", + nativeName: "Svenska", + }, + { + id: "sw", + englishName: "Swahili", + name: "Swahili - Kiswahili", + nativeName: "Kiswahili", + }, + { + id: "ta", + englishName: "Tamil", + name: "Tamil - தமிழ்", + nativeName: "தமிழ்", + }, + { + id: "te", + englishName: "Telugu", + name: "Telugu - తెలుగు", + nativeName: "తెలుగు", + }, + { + id: "tg", + englishName: "Tajik", + name: "Tajik - Тоҷикӣ", + nativeName: "Тоҷикӣ", + }, + { + id: "th", + englishName: "Thai", + name: "Thai - ไทย", + nativeName: "ไทย", + }, + { + id: "ti", + englishName: "Tigrinya", + name: "Tigrinya - ትግርኛ", + nativeName: "ትግርኛ", + }, + { + id: "tk", + englishName: "Turkmen", + name: "Turkmen - Türkmen", + nativeName: "Türkmen", + }, + { + id: "tl", + englishName: "Tagalog", + name: "Tagalog - Wikang Tagalog", + nativeName: "Wikang Tagalog", + }, + { + id: "tn", + englishName: "Tswana", + name: "Tswana - Setswana", + nativeName: "Setswana", + }, + { + id: "to", + englishName: "Tonga", + name: "Tonga - Faka Tonga", + nativeName: "Faka Tonga", + }, + { + id: "tr", + englishName: "Turkish", + name: "Turkish - Türkçe", + nativeName: "Türkçe", + }, + { + id: "ts", + englishName: "Tsonga", + name: "Tsonga - Xitsonga", + nativeName: "Xitsonga", + }, + { + id: "tt", + englishName: "Tatar", + name: "Tatar - Татар теле", + nativeName: "Татар теле", + }, + { + id: "tw", + englishName: "Twi", + name: "Twi - Twi", + nativeName: "Twi", + }, + { + id: "ty", + englishName: "Tahitian", + name: "Tahitian - Reo Tahiti", + nativeName: "Reo Tahiti", + }, + { + id: "ug", + englishName: "Uyghur", + name: "Uyghur - ئۇيغۇرچە‎", + nativeName: "ئۇيغۇرچە‎", + }, + { + id: "uk", + englishName: "Ukrainian", + name: "Ukrainian - Українська", + nativeName: "Українська", + }, + { + id: "ur", + englishName: "Urdu", + name: "Urdu - اردو", + nativeName: "اردو", + }, + { + id: "uz", + englishName: "Uzbek", + name: "Uzbek - Ўзбек", + nativeName: "Ўзбек", + }, + { + id: "ve", + englishName: "Venda", + name: "Venda - Tshivenḓa", + nativeName: "Tshivenḓa", + }, + { + id: "vi", + englishName: "Vietnamese", + name: "Vietnamese - Tiếng Việt", + nativeName: "Tiếng Việt", + }, + { + id: "vo", + englishName: "Volapük", + name: "Volapük - Volapük", + nativeName: "Volapük", + }, + { + id: "wa", + englishName: "Walloon", + name: "Walloon - Walon", + nativeName: "Walon", + }, + { + id: "wo", + englishName: "Wolof", + name: "Wolof - Wollof", + nativeName: "Wollof", + }, + { + id: "xh", + englishName: "Xhosa", + name: "Xhosa - IsiXhosa", + nativeName: "IsiXhosa", + }, + { + id: "yi", + englishName: "Yiddish", + name: "Yiddish - ייִדיש", + nativeName: "ייִדיש", + }, + { + id: "yo", + englishName: "Yoruba", + name: "Yoruba - Yorùbá", + nativeName: "Yorùbá", + }, + { + id: "za", + englishName: "Zhuang", + name: "Zhuang - Saɯ cueŋƅ", + nativeName: "Saɯ cueŋƅ", + }, + { + id: "zh", + englishName: "Chinese", + name: "Chinese - 中文", + nativeName: "中文", + }, + { + id: "zu", + englishName: "Zulu", + name: "Zulu - IsiZulu", + nativeName: "IsiZulu", + }, +]; From 9e961223f6edae1b66621ce16f420bb16843b800 Mon Sep 17 00:00:00 2001 From: frost768 Date: Thu, 6 Apr 2023 01:48:07 +0300 Subject: [PATCH 2/8] settings modal --- src/components/Dropdown.tsx | 2 +- src/components/layout/Modal.tsx | 9 +- src/components/layout/Navigation.tsx | 14 +- src/setup/locales/en/translation.json | 5 + src/state/settings/context.tsx | 21 +-- src/state/settings/store.ts | 28 +++- src/state/settings/types.ts | 18 ++- .../actions/CaptionRendererAction.tsx | 9 +- src/views/SettingsModal.tsx | 142 ++++++++++++++++++ 9 files changed, 228 insertions(+), 20 deletions(-) create mode 100644 src/views/SettingsModal.tsx diff --git a/src/components/Dropdown.tsx b/src/components/Dropdown.tsx index 84ab2957..9321e1fe 100644 --- a/src/components/Dropdown.tsx +++ b/src/components/Dropdown.tsx @@ -37,7 +37,7 @@ export function Dropdown(props: DropdownProps) { leaveFrom="opacity-100" leaveTo="opacity-0" > - + {props.options.map((opt) => ( diff --git a/src/components/layout/Modal.tsx b/src/components/layout/Modal.tsx index 7a1c3b64..8ae2f58f 100644 --- a/src/components/layout/Modal.tsx +++ b/src/components/layout/Modal.tsx @@ -35,9 +35,14 @@ export function Modal(props: Props) { ); } -export function ModalCard(props: { children?: ReactNode }) { +export function ModalCard(props: { className?: string; children?: ReactNode }) { return ( -
+
{props.children}
); diff --git a/src/components/layout/Navigation.tsx b/src/components/layout/Navigation.tsx index 4fe1864f..836c6206 100644 --- a/src/components/layout/Navigation.tsx +++ b/src/components/layout/Navigation.tsx @@ -1,9 +1,10 @@ -import { ReactNode } from "react"; +import { ReactNode, useState } from "react"; import { Link } from "react-router-dom"; import { IconPatch } from "@/components/buttons/IconPatch"; import { Icons } from "@/components/Icon"; import { conf } from "@/setup/config"; import { useBannerSize } from "@/hooks/useBanner"; +import SettingsModal from "@/views/SettingsModal"; import { BrandPill } from "./BrandPill"; export interface NavigationProps { @@ -13,7 +14,7 @@ export interface NavigationProps { export function Navigation(props: NavigationProps) { const bannerHeight = useBannerSize(); - + const [showModal, setShowModal] = useState(false); return (
+ { + setShowModal(true); + }} + />
+ setShowModal(false)} /> ); } diff --git a/src/setup/locales/en/translation.json b/src/setup/locales/en/translation.json index 1838b63c..71ee7064 100644 --- a/src/setup/locales/en/translation.json +++ b/src/setup/locales/en/translation.json @@ -99,6 +99,11 @@ "fatalError": "The video player encounted a fatal error, please report it to the <0>Discord server or on <1>GitHub." } }, + "settings": { + "title": "Settings", + "language":"Language", + "captionLanguage": "Caption Language" + }, "v3": { "newSiteTitle": "New version now released!", "newDomain": "https://movie-web.app", diff --git a/src/state/settings/context.tsx b/src/state/settings/context.tsx index 030833cc..be7a92e0 100644 --- a/src/state/settings/context.tsx +++ b/src/state/settings/context.tsx @@ -1,14 +1,15 @@ import { useStore } from "@/utils/storage"; import { createContext, ReactNode, useContext, useMemo } from "react"; +import { LangCode } from "@/setup/iso6391"; import { SettingsStore } from "./store"; import { MWSettingsData } from "./types"; interface MWSettingsDataSetters { - setLanguage(language: string): void; + setCaptionLanguage(language: LangCode): void; setCaptionDelay(delay: number): void; setCaptionColor(color: string): void; setCaptionFontSize(size: number): void; - setCaptionBackgroundColor(backgroundColor: string): void; + setCaptionBackgroundColor(backgroundColor: number): void; } type MWSettingsDataWrapper = MWSettingsData & MWSettingsDataSetters; const SettingsContext = createContext(null as any); @@ -17,16 +18,15 @@ export function SettingsProvider(props: { children: ReactNode }) { return Math.max(min, Math.min(value, max)); } const [settings, setSettings] = useStore(SettingsStore); - const context: MWSettingsDataWrapper = useMemo(() => { const settingsContext: MWSettingsDataWrapper = { ...settings, - setLanguage(language) { + setCaptionLanguage(language) { setSettings((oldSettings) => { - return { - ...oldSettings, - language, - }; + const captionSettings = oldSettings.captionSettings; + captionSettings.language = language; + const newSettings = oldSettings; + return newSettings; }); }, setCaptionDelay(delay: number) { @@ -56,7 +56,10 @@ export function SettingsProvider(props: { children: ReactNode }) { setCaptionBackgroundColor(backgroundColor) { setSettings((oldSettings) => { const style = oldSettings.captionSettings.style; - style.backgroundColor = backgroundColor; + style.backgroundColor = `${style.backgroundColor.substring( + 0, + 7 + )}${backgroundColor.toString(16).padStart(2, "0")}`; const newSettings = oldSettings; return newSettings; }); diff --git a/src/state/settings/store.ts b/src/state/settings/store.ts index c854dc04..e8c629c1 100644 --- a/src/state/settings/store.ts +++ b/src/state/settings/store.ts @@ -1,11 +1,11 @@ import { createVersionedStore } from "@/utils/storage"; -import { MWSettingsData } from "./types"; +import { MWSettingsData, MWSettingsDataV1 } from "./types"; export const SettingsStore = createVersionedStore() .setKey("mw-settings") .addVersion({ version: 0, - create(): MWSettingsData { + create(): MWSettingsDataV1 { return { language: "en", captionSettings: { @@ -18,5 +18,29 @@ export const SettingsStore = createVersionedStore() }, }; }, + migrate(data: MWSettingsDataV1): MWSettingsData { + return { + captionSettings: { + language: "none", + ...data.captionSettings, + }, + }; + }, + }) + .addVersion({ + version: 1, + create(): MWSettingsData { + return { + captionSettings: { + delay: 0, + language: "none", + style: { + color: "#ffffff", + fontSize: 25, + backgroundColor: "#00000096", + }, + }, + }; + }, }) .build(); diff --git a/src/state/settings/types.ts b/src/state/settings/types.ts index b793308d..e32bd685 100644 --- a/src/state/settings/types.ts +++ b/src/state/settings/types.ts @@ -1,3 +1,5 @@ +import { LangCode } from "@/setup/iso6391"; + export interface CaptionStyleSettings { color: string; /** @@ -7,7 +9,7 @@ export interface CaptionStyleSettings { backgroundColor: string; } -export interface CaptionSettings { +export interface CaptionSettingsV1 { /** * Range is [-10, 10]s */ @@ -15,7 +17,19 @@ export interface CaptionSettings { style: CaptionStyleSettings; } +export interface CaptionSettings { + language: LangCode; + /** + * Range is [-10, 10]s + */ + delay: number; + style: CaptionStyleSettings; +} +export interface MWSettingsDataV1 { + language: LangCode; + captionSettings: CaptionSettingsV1; +} + export interface MWSettingsData { - language: string; captionSettings: CaptionSettings; } diff --git a/src/video/components/actions/CaptionRendererAction.tsx b/src/video/components/actions/CaptionRendererAction.tsx index ab7edba0..f3a65f52 100644 --- a/src/video/components/actions/CaptionRendererAction.tsx +++ b/src/video/components/actions/CaptionRendererAction.tsx @@ -8,7 +8,7 @@ import { useVideoPlayerDescriptor } from "../../state/hooks"; import { useProgress } from "../../state/logic/progress"; import { useSource } from "../../state/logic/source"; -function CaptionCue({ text }: { text?: string }) { +export function CaptionCue({ text, scale }: { text?: string; scale?: number }) { const { captionSettings } = useSettings(); const textWithNewlines = (text || "").replaceAll(/\r?\n/g, "
"); @@ -22,9 +22,14 @@ function CaptionCue({ text }: { text?: string }) { return (

void; + show: boolean; +}) { + const { + captionSettings, + setCaptionLanguage, + setCaptionBackgroundColor, + setCaptionColor, + setCaptionFontSize, + } = useSettings(); + const { t, i18n } = useTranslation(); + + const colors = ["#ffffff", "#00ffff", "#ffff00"]; + const selectedCaptionLanguage = useMemo( + () => captionLanguages.find((l) => l.id === captionSettings.language)!, + [captionSettings.language] + ); + const captionBackgroundOpacity = ( + (parseInt(captionSettings.style.backgroundColor.substring(7, 9), 16) / + 255) * + 100 + ).toFixed(0); + return ( + + +

+ {t("settings.title")} +
props.onClose()} className="hover:cursor-pointer"> + +
+
+
+
+ + l.id === i18n.language)! + } + setSelectedItem={(val) => { + i18n.changeLanguage(val.id); + }} + options={appLanguageOptions} + /> +
+
+ + { + setCaptionLanguage(val.id as LangCode); + }} + options={captionLanguages} + /> +
+
+
+
+ setCaptionFontSize(e.target.valueAsNumber)} + /> + + setCaptionBackgroundColor(e.target.valueAsNumber) + } + /> +
+ +
+ {colors.map((color) => ( +
setCaptionColor(color)} + > +
+ +
+ ))} +
+
+
+
+ {selectedCaptionLanguage.id !== "none" ? ( +
+ +
+ ) : null} +
+
+ + + ); +} From 21780576339ecf20f0b1e53bf20605bfb20f146b Mon Sep 17 00:00:00 2001 From: frost768 Date: Thu, 6 Apr 2023 01:49:33 +0300 Subject: [PATCH 3/8] auto select subtitle --- src/backend/helpers/captions.ts | 4 ++ .../controllers/SourceController.tsx | 48 +++++++++++++++++-- .../popouts/CaptionSelectionPopout.tsx | 7 +-- .../popouts/CaptionSettingsPopout.tsx | 9 +--- src/views/developer/VideoTesterView.tsx | 1 + src/views/media/MediaView.tsx | 1 + 6 files changed, 54 insertions(+), 16 deletions(-) diff --git a/src/backend/helpers/captions.ts b/src/backend/helpers/captions.ts index 83edaa84..b5e40108 100644 --- a/src/backend/helpers/captions.ts +++ b/src/backend/helpers/captions.ts @@ -4,6 +4,10 @@ import DOMPurify from "dompurify"; import { parse, detect, list } from "subsrt-ts"; import { ContentCaption } from "subsrt-ts/dist/types/handler"; +export const customCaption = "external-custom"; +export function makeCaptionId(caption: MWCaption, isLinked: boolean): string { + return isLinked ? `linked-${caption.langIso}` : `external-${caption.langIso}`; +} export const subtitleTypeList = list().map((type) => `.${type}`); export const sanitize = DOMPurify.sanitize; export async function getCaptionUrl(caption: MWCaption): Promise { diff --git a/src/video/components/controllers/SourceController.tsx b/src/video/components/controllers/SourceController.tsx index 14d5ad93..fe98a685 100644 --- a/src/video/components/controllers/SourceController.tsx +++ b/src/video/components/controllers/SourceController.tsx @@ -1,4 +1,11 @@ -import { MWStreamQuality, MWStreamType } from "@/backend/helpers/streams"; +import { getCaptionUrl, makeCaptionId } from "@/backend/helpers/captions"; +import { + MWCaption, + MWStreamQuality, + MWStreamType, +} from "@/backend/helpers/streams"; +import { captionLanguages } from "@/setup/iso6391"; +import { useSettings } from "@/state/settings"; import { useInitialized } from "@/video/components/hooks/useInitialized"; import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { useControls } from "@/video/state/logic/controls"; @@ -10,6 +17,19 @@ interface SourceControllerProps { quality: MWStreamQuality; providerId?: string; embedId?: string; + captions: MWCaption[]; +} +async function tryFetch(captions: MWCaption[]) { + for (let i = 0; i < captions.length; i += 1) { + const caption = captions[i]; + try { + const blobUrl = await getCaptionUrl(caption); + return { caption, blobUrl }; + } catch (error) { + continue; + } + } + return null; } export function SourceController(props: SourceControllerProps) { @@ -17,13 +37,35 @@ export function SourceController(props: SourceControllerProps) { const controls = useControls(descriptor); const { initialized } = useInitialized(descriptor); const didInitialize = useRef(false); - + const { captionSettings } = useSettings(); useEffect(() => { if (didInitialize.current) return; if (!initialized) return; controls.setSource(props); + // get preferred language + const preferredLanguage = captionLanguages.find( + (v) => v.id === captionSettings.language + ); + if (!preferredLanguage) return; + const captions = props.captions.filter( + (v) => + // langIso may contain the English name or the native name of the language + v.langIso.indexOf(preferredLanguage.englishName) !== -1 || + v.langIso.indexOf(preferredLanguage.nativeName) !== -1 + ); + if (!captions) return; + // caption url can return a response other than 200 + // that's why we fetch until we get a 200 response + tryFetch(captions).then((response) => { + // none of them were successful + if (!response) return; + // set the preferred language + const id = makeCaptionId(response.caption, true); + controls.setCaption(id, response.blobUrl); + }); + didInitialize.current = true; - }, [props, controls, initialized]); + }, [props, controls, initialized, captionSettings.language]); return null; } diff --git a/src/video/components/popouts/CaptionSelectionPopout.tsx b/src/video/components/popouts/CaptionSelectionPopout.tsx index 2ae9fced..3f595757 100644 --- a/src/video/components/popouts/CaptionSelectionPopout.tsx +++ b/src/video/components/popouts/CaptionSelectionPopout.tsx @@ -1,5 +1,7 @@ import { + customCaption, getCaptionUrl, + makeCaptionId, parseSubtitles, subtitleTypeList, } from "@/backend/helpers/captions"; @@ -17,11 +19,6 @@ import { useMemo, useRef } from "react"; import { useTranslation } from "react-i18next"; import { PopoutListEntry, PopoutSection } from "./PopoutUtils"; -const customCaption = "external-custom"; -function makeCaptionId(caption: MWCaption, isLinked: boolean): string { - return isLinked ? `linked-${caption.langIso}` : `external-${caption.langIso}`; -} - export function CaptionSelectionPopout(props: { router: ReturnType; prefix: string; diff --git a/src/video/components/popouts/CaptionSettingsPopout.tsx b/src/video/components/popouts/CaptionSettingsPopout.tsx index 09bf6eea..d4f212a5 100644 --- a/src/video/components/popouts/CaptionSettingsPopout.tsx +++ b/src/video/components/popouts/CaptionSettingsPopout.tsx @@ -106,14 +106,7 @@ export function CaptionSettingsPopout(props: { captionSettings.style.backgroundColor.substring(7, 9), 16 )} - onChange={(e) => - setCaptionBackgroundColor( - `${captionSettings.style.backgroundColor.substring( - 0, - 7 - )}${e.target.valueAsNumber.toString(16)}` - ) - } + onChange={(e) => setCaptionBackgroundColor(e.target.valueAsNumber)} />
diff --git a/src/views/media/MediaView.tsx b/src/views/media/MediaView.tsx index b674fb9f..c2ee94e7 100644 --- a/src/views/media/MediaView.tsx +++ b/src/views/media/MediaView.tsx @@ -148,6 +148,7 @@ export function MediaViewPlayer(props: MediaViewPlayerProps) { quality={props.stream.quality} embedId={props.stream.embedId} providerId={props.stream.providerId} + captions={props.stream.captions} /> Date: Thu, 6 Apr 2023 04:34:59 +0300 Subject: [PATCH 4/8] fix migration --- src/backend/providers/superstream/index.ts | 2 +- src/state/settings/context.tsx | 9 +++++++++ src/state/settings/store.ts | 2 ++ src/state/settings/types.ts | 1 + 4 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/backend/providers/superstream/index.ts b/src/backend/providers/superstream/index.ts index 9ebe6262..a2469cdd 100644 --- a/src/backend/providers/superstream/index.ts +++ b/src/backend/providers/superstream/index.ts @@ -230,7 +230,7 @@ registerProvider({ const sub = subtitle; sub.subtitles = subtitle.subtitles.filter((subFile: any) => { const extension = subFile.file_path.substring( - sub.file_path.length - 3 + subFile.file_path.length - 3 ); return [MWCaptionType.SRT, MWCaptionType.VTT].includes(extension); }); diff --git a/src/state/settings/context.tsx b/src/state/settings/context.tsx index be7a92e0..8efba361 100644 --- a/src/state/settings/context.tsx +++ b/src/state/settings/context.tsx @@ -5,6 +5,7 @@ import { SettingsStore } from "./store"; import { MWSettingsData } from "./types"; interface MWSettingsDataSetters { + setLanguage(language: LangCode): void; setCaptionLanguage(language: LangCode): void; setCaptionDelay(delay: number): void; setCaptionColor(color: string): void; @@ -21,6 +22,14 @@ export function SettingsProvider(props: { children: ReactNode }) { const context: MWSettingsDataWrapper = useMemo(() => { const settingsContext: MWSettingsDataWrapper = { ...settings, + setLanguage(language) { + setSettings((oldSettings) => { + return { + ...oldSettings, + language, + }; + }); + }, setCaptionLanguage(language) { setSettings((oldSettings) => { const captionSettings = oldSettings.captionSettings; diff --git a/src/state/settings/store.ts b/src/state/settings/store.ts index e8c629c1..55ede71e 100644 --- a/src/state/settings/store.ts +++ b/src/state/settings/store.ts @@ -20,6 +20,7 @@ export const SettingsStore = createVersionedStore() }, migrate(data: MWSettingsDataV1): MWSettingsData { return { + language: data.language, captionSettings: { language: "none", ...data.captionSettings, @@ -31,6 +32,7 @@ export const SettingsStore = createVersionedStore() version: 1, create(): MWSettingsData { return { + language: "en", captionSettings: { delay: 0, language: "none", diff --git a/src/state/settings/types.ts b/src/state/settings/types.ts index e32bd685..c894be9c 100644 --- a/src/state/settings/types.ts +++ b/src/state/settings/types.ts @@ -31,5 +31,6 @@ export interface MWSettingsDataV1 { } export interface MWSettingsData { + language: LangCode; captionSettings: CaptionSettings; } From 2eab07b8b693b63d8a76d8fba4864d9a61cb8a56 Mon Sep 17 00:00:00 2001 From: frost768 Date: Thu, 6 Apr 2023 04:35:20 +0300 Subject: [PATCH 5/8] modal customization --- src/components/layout/Modal.tsx | 2 +- src/views/SettingsModal.tsx | 207 +++++++++++++++++--------------- 2 files changed, 111 insertions(+), 98 deletions(-) diff --git a/src/components/layout/Modal.tsx b/src/components/layout/Modal.tsx index 8ae2f58f..aa25ca7a 100644 --- a/src/components/layout/Modal.tsx +++ b/src/components/layout/Modal.tsx @@ -39,7 +39,7 @@ export function ModalCard(props: { className?: string; children?: ReactNode }) { return (
diff --git a/src/views/SettingsModal.tsx b/src/views/SettingsModal.tsx index b6ad9c19..b05ebe14 100644 --- a/src/views/SettingsModal.tsx +++ b/src/views/SettingsModal.tsx @@ -5,9 +5,9 @@ import { useSettings } from "@/state/settings"; import { useTranslation } from "react-i18next"; import { CaptionCue } from "@/video/components/actions/CaptionRendererAction"; import { Slider } from "@/video/components/popouts/CaptionSettingsPopout"; -import { appLanguageOptions } from "@/setup/i18n"; import { LangCode, captionLanguages } from "@/setup/iso6391"; import { useMemo } from "react"; +import { appLanguageOptions } from "@/setup/i18n"; export default function SettingsModal(props: { onClose: () => void; @@ -15,6 +15,8 @@ export default function SettingsModal(props: { }) { const { captionSettings, + language, + setLanguage, setCaptionLanguage, setCaptionBackgroundColor, setCaptionColor, @@ -34,106 +36,117 @@ export default function SettingsModal(props: { ).toFixed(0); return ( - -
- {t("settings.title")} -
props.onClose()} className="hover:cursor-pointer"> - -
-
-
-
- - l.id === i18n.language)! - } - setSelectedItem={(val) => { - i18n.changeLanguage(val.id); - }} - options={appLanguageOptions} - /> -
-
- - { - setCaptionLanguage(val.id as LangCode); - }} - options={captionLanguages} - /> -
-
-
-
- setCaptionFontSize(e.target.valueAsNumber)} - /> - - setCaptionBackgroundColor(e.target.valueAsNumber) - } - /> -
- -
- {colors.map((color) => ( -
setCaptionColor(color)} - > -
- -
- ))} -
+ +
+
+ {t("settings.title")} +
props.onClose()} + className="hover:cursor-pointer" + > +
-
- {selectedCaptionLanguage.id !== "none" ? ( -
- +
+
+ + l.id === language)! + } + setSelectedItem={(val) => { + i18n.changeLanguage(val.id); + setLanguage(val.id as LangCode); + }} + options={appLanguageOptions} />
- ) : null} +
+ + { + setCaptionLanguage(val.id as LangCode); + }} + options={captionLanguages} + /> +
+
+ setCaptionFontSize(e.target.valueAsNumber)} + /> + + setCaptionBackgroundColor(e.target.valueAsNumber) + } + /> +
+ +
+ {colors.map((color) => ( +
setCaptionColor(color)} + > +
+ +
+ ))} +
+
+
+
+
+
+
+ {selectedCaptionLanguage.id !== "none" ? ( +
+ +
+ ) : null} +
+
From b9b0380dfe75080774cad0fef3b38e8e4282e696 Mon Sep 17 00:00:00 2001 From: frost768 Date: Mon, 10 Apr 2023 00:55:23 +0300 Subject: [PATCH 6/8] suggested changes --- src/components/CaptionColorSelector.tsx | 29 +++++++++ src/components/layout/Modal.tsx | 2 +- src/setup/iso6391.ts | 4 +- .../actions/CaptionRendererAction.tsx | 8 +-- .../popouts/CaptionSettingsPopout.tsx | 29 ++------- src/views/SettingsModal.tsx | 64 +++++++++---------- 6 files changed, 68 insertions(+), 68 deletions(-) create mode 100644 src/components/CaptionColorSelector.tsx diff --git a/src/components/CaptionColorSelector.tsx b/src/components/CaptionColorSelector.tsx new file mode 100644 index 00000000..3d286f78 --- /dev/null +++ b/src/components/CaptionColorSelector.tsx @@ -0,0 +1,29 @@ +import { useSettings } from "@/state/settings"; +import { Icon, Icons } from "./Icon"; + +export const colors = ["#ffffff", "#00ffff", "#ffff00"]; +export default function CaptionColorSelector({ color }: { color: string }) { + const { captionSettings, setCaptionColor } = useSettings(); + return ( +
setCaptionColor(color)} + > +
+ +
+ ); +} diff --git a/src/components/layout/Modal.tsx b/src/components/layout/Modal.tsx index aa25ca7a..d5a910c1 100644 --- a/src/components/layout/Modal.tsx +++ b/src/components/layout/Modal.tsx @@ -40,7 +40,7 @@ export function ModalCard(props: { className?: string; children?: ReactNode }) {
{props.children} diff --git a/src/setup/iso6391.ts b/src/setup/iso6391.ts index 3677560a..0d12f39c 100644 --- a/src/setup/iso6391.ts +++ b/src/setup/iso6391.ts @@ -184,7 +184,7 @@ export type LangCode = | "za" | "zh" | "zu"; -type CaptionLanguageOptions = { +export type CaptionLanguageOption = { id: LangCode; name: string; englishName: string; @@ -212,7 +212,7 @@ type CaptionLanguageOptions = { // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -export const captionLanguages: CaptionLanguageOptions[] = [ +export const captionLanguages: CaptionLanguageOption[] = [ { id: "none", englishName: "None", diff --git a/src/video/components/actions/CaptionRendererAction.tsx b/src/video/components/actions/CaptionRendererAction.tsx index f3a65f52..664cffef 100644 --- a/src/video/components/actions/CaptionRendererAction.tsx +++ b/src/video/components/actions/CaptionRendererAction.tsx @@ -22,14 +22,10 @@ export function CaptionCue({ text, scale }: { text?: string; scale?: number }) { return (

; @@ -16,11 +18,9 @@ export function CaptionSettingsPopout(props: { const { captionSettings, setCaptionBackgroundColor, - setCaptionColor, setCaptionDelay, setCaptionFontSize, } = useSettings(); - const colors = ["#ffffff", "#00ffff", "#ffff00"]; return ( setCaptionDelay(e.target.valueAsNumber)} />

{colors.map((color) => ( -
setCaptionColor(color)} - > -
- -
+ ))}
diff --git a/src/views/SettingsModal.tsx b/src/views/SettingsModal.tsx index b05ebe14..073e03c9 100644 --- a/src/views/SettingsModal.tsx +++ b/src/views/SettingsModal.tsx @@ -4,10 +4,18 @@ import { Modal, ModalCard } from "@/components/layout/Modal"; import { useSettings } from "@/state/settings"; import { useTranslation } from "react-i18next"; import { CaptionCue } from "@/video/components/actions/CaptionRendererAction"; -import { Slider } from "@/video/components/popouts/CaptionSettingsPopout"; -import { LangCode, captionLanguages } from "@/setup/iso6391"; +import { + CaptionLanguageOption, + LangCode, + captionLanguages, +} from "@/setup/iso6391"; import { useMemo } from "react"; import { appLanguageOptions } from "@/setup/i18n"; +import CaptionColorSelector, { + colors, +} from "@/components/CaptionColorSelector"; +import { Slider } from "@/components/Slider"; +import { conf } from "@/setup/config"; export default function SettingsModal(props: { onClose: () => void; @@ -19,16 +27,18 @@ export default function SettingsModal(props: { setLanguage, setCaptionLanguage, setCaptionBackgroundColor, - setCaptionColor, setCaptionFontSize, } = useSettings(); const { t, i18n } = useTranslation(); - const colors = ["#ffffff", "#00ffff", "#ffff00"]; const selectedCaptionLanguage = useMemo( - () => captionLanguages.find((l) => l.id === captionSettings.language)!, + () => captionLanguages.find((l) => l.id === captionSettings.language), [captionSettings.language] - ); + ) as CaptionLanguageOption; + const appLanguage = useMemo( + () => appLanguageOptions.find((l) => l.id === language), + [language] + ) as CaptionLanguageOption; const captionBackgroundOpacity = ( (parseInt(captionSettings.style.backgroundColor.substring(7, 9), 16) / 255) * @@ -54,9 +64,7 @@ export default function SettingsModal(props: { {t("settings.language")} l.id === language)! - } + selectedItem={appLanguage} setSelectedItem={(val) => { i18n.changeLanguage(val.id); setLanguage(val.id as LangCode); @@ -78,7 +86,11 @@ export default function SettingsModal(props: {
setCaptionFontSize(e.target.valueAsNumber)} />
{colors.map((color) => ( -
setCaptionColor(color)} - > -
- -
+ ))}
@@ -149,6 +142,7 @@ export default function SettingsModal(props: {
+
v{conf().APP_VERSION}
); From 546b008b2e2bb7b3063b703d449d2125779ab4c9 Mon Sep 17 00:00:00 2001 From: frost768 Date: Mon, 10 Apr 2023 22:10:11 +0300 Subject: [PATCH 7/8] show text when no caption language is selected --- src/setup/iso6391.ts | 2 +- src/views/SettingsModal.tsx | 14 ++++++-------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/setup/iso6391.ts b/src/setup/iso6391.ts index 0d12f39c..c20580b8 100644 --- a/src/setup/iso6391.ts +++ b/src/setup/iso6391.ts @@ -217,7 +217,7 @@ export const captionLanguages: CaptionLanguageOption[] = [ id: "none", englishName: "None", name: "None", - nativeName: "None", + nativeName: "No caption language selected", }, { id: "aa", diff --git a/src/views/SettingsModal.tsx b/src/views/SettingsModal.tsx index 073e03c9..49f06194 100644 --- a/src/views/SettingsModal.tsx +++ b/src/views/SettingsModal.tsx @@ -130,14 +130,12 @@ export default function SettingsModal(props: {
- {selectedCaptionLanguage.id !== "none" ? ( -
- -
- ) : null} +
+ +
From 2239c186a585933e797f1ac6542ed67b8fe89da6 Mon Sep 17 00:00:00 2001 From: frost768 Date: Thu, 20 Apr 2023 21:43:51 +0300 Subject: [PATCH 8/8] modal background changed --- src/components/layout/Modal.tsx | 2 +- src/views/SettingsModal.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/layout/Modal.tsx b/src/components/layout/Modal.tsx index d5a910c1..b3e7a22e 100644 --- a/src/components/layout/Modal.tsx +++ b/src/components/layout/Modal.tsx @@ -39,7 +39,7 @@ export function ModalCard(props: { className?: string; children?: ReactNode }) { return (
diff --git a/src/views/SettingsModal.tsx b/src/views/SettingsModal.tsx index 49f06194..b3ba74ed 100644 --- a/src/views/SettingsModal.tsx +++ b/src/views/SettingsModal.tsx @@ -46,7 +46,7 @@ export default function SettingsModal(props: { ).toFixed(0); return ( - +
{t("settings.title")}