diff --git a/bin/update-translations.cjs b/bin/update-translations.cjs index 35752c829..204595901 100644 --- a/bin/update-translations.cjs +++ b/bin/update-translations.cjs @@ -8,8 +8,8 @@ * 1. Path to CreateAI tool translation strings directory. * 2. Path to machine-learning-strings.json translation strings directory. * - * To only update MakeCode block translations, pass path to - * machine-learning-strings.json translation strings directory as an argument. + * To only update CreateAI tool translations, pass path to CreateAI tool + * translation strings directory as an argument. * * Manually run `npm run i18n:compile` after. * @@ -55,7 +55,7 @@ if (args.length === 0 || args.length > 2) { } const [createAiTranslationsFilepath, mlTranslationsFilepath] = - args.length === 1 ? [null, args[0]] : args; + args.length === 1 ? [args[0], null] : args; languages.forEach((language) => { const lowerLang = language.toLowerCase(); @@ -76,10 +76,14 @@ languages.forEach((language) => { : `${createAiTranslationsFilepath}/${language}/ui.en.json`; const langMessages = getFileJSONContent(srcLangFilepath); - const mlFilepath = `${mlTranslationsFilepath}/${language}/machine-learning-strings.json`; - const mlStrings = getFileJSONContent(mlFilepath); + // Update machine learning strings. + let messagesToAdd = {} + if (mlTranslationsFilepath) { + const mlFilepath = `${mlTranslationsFilepath}/${language}/machine-learning-strings.json`; + const mlStrings = getFileJSONContent(mlFilepath); + messagesToAdd = getMessagesToAdd(mlStrings, langMessages); + } - const messagesToAdd = getMessagesToAdd(mlStrings, langMessages); fs.writeFileSync( outputFilepath, JSON.stringify({ ...langMessages, ...messagesToAdd }) diff --git a/lang/ui.ca.json b/lang/ui.ca.json index 0b69168ee..8a2bc1912 100644 --- a/lang/ui.ca.json +++ b/lang/ui.ca.json @@ -871,6 +871,30 @@ "defaultMessage": "Idioma", "description": "Language option text" }, + "language-fully-supported-heading": { + "defaultMessage": "Fully supported", + "description": "Fully supported languages heading text" + }, + "language-partially-supported-heading": { + "defaultMessage": "Partially supported", + "description": "Partially supported languages heading text" + }, + "language-support-checked": { + "defaultMessage": "Compatible", + "description": "Aria label for ticked checkbox for language support" + }, + "language-support-unchecked": { + "defaultMessage": "Incompatible", + "description": "Aria label for unticked checkbox for language support" + }, + "language-supported-for": { + "defaultMessage": "Traduccions compatibles per a:", + "description": "Text introducing list of translated areas for a given language (areas: Microsoft MakeCode, micro:bit CreateAI UI itself)" + }, + "language-toast-title": { + "defaultMessage": "L'idioma no està disponible totalment", + "description": "Language support toast notification title" + }, "learn-about-firewall-requirements-action": { "defaultMessage": "Més informació sobre els requisits del tallafoc", "description": "Link to support article for firewall requirements" diff --git a/lang/ui.en.json b/lang/ui.en.json index 14d509367..15df376e5 100644 --- a/lang/ui.en.json +++ b/lang/ui.en.json @@ -871,6 +871,30 @@ "defaultMessage": "Language", "description": "Language option text" }, + "language-fully-supported-heading": { + "defaultMessage": "Fully supported", + "description": "Fully supported languages heading text" + }, + "language-partially-supported-heading": { + "defaultMessage": "Partially supported", + "description": "Partially supported languages heading text" + }, + "language-support-checked": { + "defaultMessage": "Supported", + "description": "Aria label for ticked checkbox for language support" + }, + "language-support-unchecked": { + "defaultMessage": "Unsupported", + "description": "Aria label for unticked checkbox for language support" + }, + "language-supported-for": { + "defaultMessage": "Translations supported for:", + "description": "Text introducing list of translated areas for a given language (areas: Microsoft MakeCode, micro:bit CreateAI UI itself)" + }, + "language-toast-title": { + "defaultMessage": "Language not fully supported", + "description": "Language support toast notification title" + }, "learn-about-firewall-requirements-action": { "defaultMessage": "Learn about firewall requirements", "description": "Link to support article for firewall requirements" diff --git a/lang/ui.es-es.json b/lang/ui.es-es.json index 838208138..c524073d4 100644 --- a/lang/ui.es-es.json +++ b/lang/ui.es-es.json @@ -871,6 +871,30 @@ "defaultMessage": "Idioma", "description": "Language option text" }, + "language-fully-supported-heading": { + "defaultMessage": "Fully supported", + "description": "Fully supported languages heading text" + }, + "language-partially-supported-heading": { + "defaultMessage": "Partially supported", + "description": "Partially supported languages heading text" + }, + "language-support-checked": { + "defaultMessage": "Admitidas", + "description": "Aria label for ticked checkbox for language support" + }, + "language-support-unchecked": { + "defaultMessage": "No admitidas", + "description": "Aria label for unticked checkbox for language support" + }, + "language-supported-for": { + "defaultMessage": "Traducciones admitidas para:", + "description": "Text introducing list of translated areas for a given language (areas: Microsoft MakeCode, micro:bit CreateAI UI itself)" + }, + "language-toast-title": { + "defaultMessage": "El idioma no es soportado totalmente", + "description": "Language support toast notification title" + }, "learn-about-firewall-requirements-action": { "defaultMessage": "Conoce los requisitos del cortafuegos", "description": "Link to support article for firewall requirements" diff --git a/lang/ui.ja.json b/lang/ui.ja.json index f6575a79a..5d7ad2166 100644 --- a/lang/ui.ja.json +++ b/lang/ui.ja.json @@ -871,6 +871,30 @@ "defaultMessage": "言語", "description": "Language option text" }, + "language-fully-supported-heading": { + "defaultMessage": "Fully supported", + "description": "Fully supported languages heading text" + }, + "language-partially-supported-heading": { + "defaultMessage": "Partially supported", + "description": "Partially supported languages heading text" + }, + "language-support-checked": { + "defaultMessage": "対応", + "description": "Aria label for ticked checkbox for language support" + }, + "language-support-unchecked": { + "defaultMessage": "非対応", + "description": "Aria label for unticked checkbox for language support" + }, + "language-supported-for": { + "defaultMessage": "サポートされている翻訳:", + "description": "Text introducing list of translated areas for a given language (areas: Microsoft MakeCode, micro:bit CreateAI UI itself)" + }, + "language-toast-title": { + "defaultMessage": "言語が完全にサポートされていません", + "description": "Language support toast notification title" + }, "learn-about-firewall-requirements-action": { "defaultMessage": "ファイアウォール要件について調べる", "description": "Link to support article for firewall requirements" diff --git a/lang/ui.ko.json b/lang/ui.ko.json index 0bd800b29..42dc0ffe5 100644 --- a/lang/ui.ko.json +++ b/lang/ui.ko.json @@ -871,6 +871,30 @@ "defaultMessage": "언어 선택", "description": "Language option text" }, + "language-fully-supported-heading": { + "defaultMessage": "Fully supported", + "description": "Fully supported languages heading text" + }, + "language-partially-supported-heading": { + "defaultMessage": "Partially supported", + "description": "Partially supported languages heading text" + }, + "language-support-checked": { + "defaultMessage": "지원됨", + "description": "Aria label for ticked checkbox for language support" + }, + "language-support-unchecked": { + "defaultMessage": "지원되지 않음", + "description": "Aria label for unticked checkbox for language support" + }, + "language-supported-for": { + "defaultMessage": "지원되는 번역:", + "description": "Text introducing list of translated areas for a given language (areas: Microsoft MakeCode, micro:bit CreateAI UI itself)" + }, + "language-toast-title": { + "defaultMessage": "언어가 완전히 지원되지 않습니다", + "description": "Language support toast notification title" + }, "learn-about-firewall-requirements-action": { "defaultMessage": "방화벽 요구 사항에 대해 알아보기", "description": "Link to support article for firewall requirements" diff --git a/lang/ui.lol.json b/lang/ui.lol.json index 574d63906..414cd058b 100644 --- a/lang/ui.lol.json +++ b/lang/ui.lol.json @@ -871,6 +871,30 @@ "defaultMessage": "crwdns363064:0crwdne363064:0", "description": "Language option text" }, + "language-fully-supported-heading": { + "defaultMessage": "crwdns366275:0crwdne366275:0", + "description": "Fully supported languages heading text" + }, + "language-partially-supported-heading": { + "defaultMessage": "crwdns366277:0crwdne366277:0", + "description": "Partially supported languages heading text" + }, + "language-support-checked": { + "defaultMessage": "crwdns366279:0crwdne366279:0", + "description": "Aria label for ticked checkbox for language support" + }, + "language-support-unchecked": { + "defaultMessage": "crwdns366281:0crwdne366281:0", + "description": "Aria label for unticked checkbox for language support" + }, + "language-supported-for": { + "defaultMessage": "crwdns366283:0crwdne366283:0", + "description": "Text introducing list of translated areas for a given language (areas: Microsoft MakeCode, micro:bit CreateAI UI itself)" + }, + "language-toast-title": { + "defaultMessage": "crwdns366285:0crwdne366285:0", + "description": "Language support toast notification title" + }, "learn-about-firewall-requirements-action": { "defaultMessage": "crwdns363066:0crwdne363066:0", "description": "Link to support article for firewall requirements" diff --git a/lang/ui.nl.json b/lang/ui.nl.json index cd08bc883..92c7c28e6 100644 --- a/lang/ui.nl.json +++ b/lang/ui.nl.json @@ -871,6 +871,30 @@ "defaultMessage": "Taal", "description": "Language option text" }, + "language-fully-supported-heading": { + "defaultMessage": "Fully supported", + "description": "Fully supported languages heading text" + }, + "language-partially-supported-heading": { + "defaultMessage": "Partially supported", + "description": "Partially supported languages heading text" + }, + "language-support-checked": { + "defaultMessage": "Ondersteund", + "description": "Aria label for ticked checkbox for language support" + }, + "language-support-unchecked": { + "defaultMessage": "Niet ondersteund", + "description": "Aria label for unticked checkbox for language support" + }, + "language-supported-for": { + "defaultMessage": "Vertalingen ondersteund voor:", + "description": "Text introducing list of translated areas for a given language (areas: Microsoft MakeCode, micro:bit CreateAI UI itself)" + }, + "language-toast-title": { + "defaultMessage": "Taal niet volledig ondersteund", + "description": "Language support toast notification title" + }, "learn-about-firewall-requirements-action": { "defaultMessage": "Meer informatie over firewall vereisten", "description": "Link to support article for firewall requirements" diff --git a/lang/ui.pl.json b/lang/ui.pl.json index a36e48a8a..23159e28c 100644 --- a/lang/ui.pl.json +++ b/lang/ui.pl.json @@ -871,6 +871,30 @@ "defaultMessage": "Język", "description": "Language option text" }, + "language-fully-supported-heading": { + "defaultMessage": "Fully supported", + "description": "Fully supported languages heading text" + }, + "language-partially-supported-heading": { + "defaultMessage": "Partially supported", + "description": "Partially supported languages heading text" + }, + "language-support-checked": { + "defaultMessage": "Wspierane", + "description": "Aria label for ticked checkbox for language support" + }, + "language-support-unchecked": { + "defaultMessage": "Niewspierany", + "description": "Aria label for unticked checkbox for language support" + }, + "language-supported-for": { + "defaultMessage": "Tłumaczenia wspierane dla:", + "description": "Text introducing list of translated areas for a given language (areas: Microsoft MakeCode, micro:bit CreateAI UI itself)" + }, + "language-toast-title": { + "defaultMessage": "Język nie w pełni obsługiwany", + "description": "Language support toast notification title" + }, "learn-about-firewall-requirements-action": { "defaultMessage": "Dowiedz się więcej o wymaganiach firewall", "description": "Link to support article for firewall requirements" diff --git a/lang/ui.pt-br.json b/lang/ui.pt-br.json index 7509dfb3c..7381c6fb0 100644 --- a/lang/ui.pt-br.json +++ b/lang/ui.pt-br.json @@ -871,6 +871,30 @@ "defaultMessage": "Idioma", "description": "Language option text" }, + "language-fully-supported-heading": { + "defaultMessage": "Fully supported", + "description": "Fully supported languages heading text" + }, + "language-partially-supported-heading": { + "defaultMessage": "Partially supported", + "description": "Partially supported languages heading text" + }, + "language-support-checked": { + "defaultMessage": "Auxiliado", + "description": "Aria label for ticked checkbox for language support" + }, + "language-support-unchecked": { + "defaultMessage": "Não auxiliado", + "description": "Aria label for unticked checkbox for language support" + }, + "language-supported-for": { + "defaultMessage": "Traduções suportadas para:", + "description": "Text introducing list of translated areas for a given language (areas: Microsoft MakeCode, micro:bit CreateAI UI itself)" + }, + "language-toast-title": { + "defaultMessage": "O idioma possui suporte parcial", + "description": "Language support toast notification title" + }, "learn-about-firewall-requirements-action": { "defaultMessage": "Saiba mais sobre os requisitos de firewall.", "description": "Link to support article for firewall requirements" diff --git a/lang/ui.zh-tw.json b/lang/ui.zh-tw.json index b3f521183..94e2db06f 100644 --- a/lang/ui.zh-tw.json +++ b/lang/ui.zh-tw.json @@ -871,6 +871,30 @@ "defaultMessage": "語言", "description": "Language option text" }, + "language-fully-supported-heading": { + "defaultMessage": "Fully supported", + "description": "Fully supported languages heading text" + }, + "language-partially-supported-heading": { + "defaultMessage": "Partially supported", + "description": "Partially supported languages heading text" + }, + "language-support-checked": { + "defaultMessage": "Supported", + "description": "Aria label for ticked checkbox for language support" + }, + "language-support-unchecked": { + "defaultMessage": "Unsupported", + "description": "Aria label for unticked checkbox for language support" + }, + "language-supported-for": { + "defaultMessage": "Translations supported for:", + "description": "Text introducing list of translated areas for a given language (areas: Microsoft MakeCode, micro:bit CreateAI UI itself)" + }, + "language-toast-title": { + "defaultMessage": "Language not fully supported", + "description": "Language support toast notification title" + }, "learn-about-firewall-requirements-action": { "defaultMessage": "瞭解防火牆要求", "description": "Link to support article for firewall requirements" diff --git a/src/components/Editor.tsx b/src/components/Editor.tsx index 5949a467d..8c0ca175f 100644 --- a/src/components/Editor.tsx +++ b/src/components/Editor.tsx @@ -11,6 +11,7 @@ import React, { forwardRef } from "react"; import { useProject } from "../hooks/project-hooks"; import { getMakeCodeLang } from "../settings"; import { useSettings } from "../store"; +import { getEditorVersionOverride } from "../editor-version"; const controllerId = "MicrobitMachineLearningTool"; @@ -27,10 +28,12 @@ const Editor = forwardRef(function Editor( return ( diff --git a/src/components/LanguageDialog.tsx b/src/components/LanguageDialog.tsx index 51b5951db..7a4c6cdb6 100644 --- a/src/components/LanguageDialog.tsx +++ b/src/components/LanguageDialog.tsx @@ -12,13 +12,32 @@ import { ModalHeader, ModalOverlay, } from "@chakra-ui/modal"; -import { HStack, Icon, Link, SimpleGrid, Text, VStack } from "@chakra-ui/react"; -import { useCallback } from "react"; -import { RiExternalLinkLine } from "react-icons/ri"; -import { FormattedMessage } from "react-intl"; +import { + BoxProps, + HStack, + Icon, + Link, + List, + ListItem, + SimpleGrid, + Stack, + Text, + Tooltip, + VStack, + useToast, +} from "@chakra-ui/react"; +import React, { useCallback, useRef, useState } from "react"; +import { + RiCheckboxBlankLine, + RiCheckboxLine, + RiErrorWarningLine, + RiExternalLinkLine, +} from "react-icons/ri"; +import { FormattedMessage, IntlShape, useIntl } from "react-intl"; import { deployment } from "../deployment"; -import { Language, supportedLanguages } from "../settings"; +import { allLanguages, Language } from "../settings"; import { useStore } from "../store"; +import { flags } from "../flags"; interface LanguageDialogProps { isOpen: boolean; @@ -42,12 +61,12 @@ export const LanguageDialog = ({ }, [onClose, setLanguage] ); - const hasPreviewLanguages = supportedLanguages.some((l) => l.preview); return ( @@ -56,36 +75,62 @@ export const LanguageDialog = ({ - - - {supportedLanguages.map((language) => ( - - ))} + + + + + + {allLanguages + .filter((l) => l.makeCode && l.ui) + .map((language) => ( + + ))} - - {" "} - - - - {hasPreviewLanguages && ( - - * These languages are an early preview of in-progress - translations. + - )} + + {allLanguages + .filter((l) => !(l.makeCode && l.ui)) + .map((language) => ( + + ))} + + - + + + {" "} + + @@ -102,27 +147,143 @@ interface LanguageCardProps { } const LanguageCard = ({ language, onChooseLanguage }: LanguageCardProps) => { + const intl = useIntl(); + const [tooltipOpen, setTooltipOpen] = useState(false); + const tooltipRef = useRef(null); + const toast = useToast(); + const handleLanguageSelect = useCallback( + (e: React.MouseEvent) => { + if (e.target !== tooltipRef.current) { + onChooseLanguage(language.id); + if (!fullySupported(language)) { + toast({ + title: intl.formatMessage({ id: "language-toast-title" }), + description: ( + + ), + status: "info", + duration: 5_000, + isClosable: true, + position: "top", + variant: "toast", + }); + } + } + }, + [intl, language, onChooseLanguage, toast] + ); + const handleTooltipClick = useCallback((e: React.MouseEvent) => { + e.stopPropagation(); + setTooltipOpen(true); + }, []); return ( ); }; + +const uiSupported = (language: Language): boolean => + language.ui === true || + (language.ui === "preview" && flags.translationPreview); + +const fullySupported = (language: Language): boolean => { + return uiSupported(language) === true && language.makeCode; +}; + +interface SupportStatementProps extends BoxProps { + language: Language; + intl: IntlShape; +} + +const SupportStatement = ({ + language, + intl, + ...rest +}: SupportStatementProps) => { + return ( + + + {intl.formatMessage({ id: "language-supported-for" })} + + + + Microsoft MakeCode + + + micro:bit CreateAI + + + + ); +}; + +const SupportedListItem = ({ + children, + supported, + intl, +}: { + children: string; + supported: boolean; + intl: IntlShape; +}) => { + return ( + + {" "} + {children} + + ); +}; diff --git a/src/editor-version.ts b/src/editor-version.ts new file mode 100644 index 000000000..d6b6df664 --- /dev/null +++ b/src/editor-version.ts @@ -0,0 +1,13 @@ +const editorVersionOverrideSessionStorageKey = "editorVersionOverride"; +export const setEditorVersionOverride = (version: string | undefined) => { + if (version) { + sessionStorage.setItem(editorVersionOverrideSessionStorageKey, version); + } else { + sessionStorage.removeItem(editorVersionOverrideSessionStorageKey); + } +}; +export const getEditorVersionOverride = (): string | undefined => { + return ( + sessionStorage.getItem(editorVersionOverrideSessionStorageKey) ?? undefined + ); +}; diff --git a/src/flags.ts b/src/flags.ts index 9831cfe53..fc66986d6 100644 --- a/src/flags.ts +++ b/src/flags.ts @@ -28,6 +28,10 @@ export type Flag = * Enables in-context Crowdin translating. */ | "translate" + /** + * Enables languages that are ready for review. + */ + | "translationPreview" /** * Flag to show links to website content for the CreateAI release. */ @@ -45,14 +49,15 @@ interface FlagMetadata { const allFlags: FlagMetadata[] = [ // Alphabetical order. - { name: "devtools", defaultOnStages: ["local"] }, { name: "exampleOptInA", defaultOnStages: ["review", "staging"] }, { name: "exampleOptInB", defaultOnStages: [] }, + { name: "devtools", defaultOnStages: ["local"] }, { name: "preReleaseNotice", defaultOnStages: ["staging"], }, { name: "translate", defaultOnStages: [] }, + { name: "translationPreview", defaultOnStages: [] }, { name: "websiteContent", defaultOnStages: ["local", "review", "staging", "production"], diff --git a/src/messages/TranslationProvider.tsx b/src/messages/TranslationProvider.tsx index a2a861792..1c6c5a5ca 100644 --- a/src/messages/TranslationProvider.tsx +++ b/src/messages/TranslationProvider.tsx @@ -7,11 +7,22 @@ import { useSettings } from "../store"; import { IntlProvider, MessageFormatElement } from "react-intl"; import { ReactNode, useEffect, useState } from "react"; import { retryAsyncLoad } from "./chunk-util"; +import { allLanguages } from "../settings"; +import { flags } from "../flags"; async function loadLocaleData(locale: string) { const lang = locale.toLowerCase(); - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - return (await import(`./ui.${lang}.json`)).default as Messages; + const languageSetting = allLanguages.find( + l => l.id.toLowerCase() === lang + ); + const importLanguage = + (flags.translationPreview && languageSetting?.ui === "preview") || + languageSetting?.ui === true; + if (importLanguage) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + return (await import(`./ui.${lang}.json`)).default as Messages; + } + return (await import("./ui.en.json")).default; } type Messages = Record | Record; diff --git a/src/messages/ui.ca.json b/src/messages/ui.ca.json index 45a79bc3d..5fb19407d 100644 --- a/src/messages/ui.ca.json +++ b/src/messages/ui.ca.json @@ -1519,6 +1519,42 @@ "value": "Idioma" } ], + "language-fully-supported-heading": [ + { + "type": 0, + "value": "Fully supported" + } + ], + "language-partially-supported-heading": [ + { + "type": 0, + "value": "Partially supported" + } + ], + "language-support-checked": [ + { + "type": 0, + "value": "Compatible" + } + ], + "language-support-unchecked": [ + { + "type": 0, + "value": "Incompatible" + } + ], + "language-supported-for": [ + { + "type": 0, + "value": "Traduccions compatibles per a:" + } + ], + "language-toast-title": [ + { + "type": 0, + "value": "L'idioma no està disponible totalment" + } + ], "learn-about-firewall-requirements-action": [ { "type": 0, diff --git a/src/messages/ui.en.json b/src/messages/ui.en.json index 4e296aae5..f6863544d 100644 --- a/src/messages/ui.en.json +++ b/src/messages/ui.en.json @@ -1533,6 +1533,42 @@ "value": "Language" } ], + "language-fully-supported-heading": [ + { + "type": 0, + "value": "Fully supported" + } + ], + "language-partially-supported-heading": [ + { + "type": 0, + "value": "Partially supported" + } + ], + "language-support-checked": [ + { + "type": 0, + "value": "Supported" + } + ], + "language-support-unchecked": [ + { + "type": 0, + "value": "Unsupported" + } + ], + "language-supported-for": [ + { + "type": 0, + "value": "Translations supported for:" + } + ], + "language-toast-title": [ + { + "type": 0, + "value": "Language not fully supported" + } + ], "learn-about-firewall-requirements-action": [ { "type": 0, diff --git a/src/messages/ui.es-es.json b/src/messages/ui.es-es.json index 1999dd986..9c05019d2 100644 --- a/src/messages/ui.es-es.json +++ b/src/messages/ui.es-es.json @@ -1533,6 +1533,42 @@ "value": "Idioma" } ], + "language-fully-supported-heading": [ + { + "type": 0, + "value": "Fully supported" + } + ], + "language-partially-supported-heading": [ + { + "type": 0, + "value": "Partially supported" + } + ], + "language-support-checked": [ + { + "type": 0, + "value": "Admitidas" + } + ], + "language-support-unchecked": [ + { + "type": 0, + "value": "No admitidas" + } + ], + "language-supported-for": [ + { + "type": 0, + "value": "Traducciones admitidas para:" + } + ], + "language-toast-title": [ + { + "type": 0, + "value": "El idioma no es soportado totalmente" + } + ], "learn-about-firewall-requirements-action": [ { "type": 0, diff --git a/src/messages/ui.ja.json b/src/messages/ui.ja.json index 40e733cd3..77c3a43d1 100644 --- a/src/messages/ui.ja.json +++ b/src/messages/ui.ja.json @@ -1513,6 +1513,42 @@ "value": "言語" } ], + "language-fully-supported-heading": [ + { + "type": 0, + "value": "Fully supported" + } + ], + "language-partially-supported-heading": [ + { + "type": 0, + "value": "Partially supported" + } + ], + "language-support-checked": [ + { + "type": 0, + "value": "対応" + } + ], + "language-support-unchecked": [ + { + "type": 0, + "value": "非対応" + } + ], + "language-supported-for": [ + { + "type": 0, + "value": "サポートされている翻訳:" + } + ], + "language-toast-title": [ + { + "type": 0, + "value": "言語が完全にサポートされていません" + } + ], "learn-about-firewall-requirements-action": [ { "type": 0, diff --git a/src/messages/ui.ko.json b/src/messages/ui.ko.json index d95111423..f9c9dd71d 100644 --- a/src/messages/ui.ko.json +++ b/src/messages/ui.ko.json @@ -1521,6 +1521,42 @@ "value": "언어 선택" } ], + "language-fully-supported-heading": [ + { + "type": 0, + "value": "Fully supported" + } + ], + "language-partially-supported-heading": [ + { + "type": 0, + "value": "Partially supported" + } + ], + "language-support-checked": [ + { + "type": 0, + "value": "지원됨" + } + ], + "language-support-unchecked": [ + { + "type": 0, + "value": "지원되지 않음" + } + ], + "language-supported-for": [ + { + "type": 0, + "value": "지원되는 번역:" + } + ], + "language-toast-title": [ + { + "type": 0, + "value": "언어가 완전히 지원되지 않습니다" + } + ], "learn-about-firewall-requirements-action": [ { "type": 0, diff --git a/src/messages/ui.lol.json b/src/messages/ui.lol.json index d0cc01242..9e77afd9b 100644 --- a/src/messages/ui.lol.json +++ b/src/messages/ui.lol.json @@ -1427,6 +1427,42 @@ "value": "crwdns363064:0crwdne363064:0" } ], + "language-fully-supported-heading": [ + { + "type": 0, + "value": "crwdns366275:0crwdne366275:0" + } + ], + "language-partially-supported-heading": [ + { + "type": 0, + "value": "crwdns366277:0crwdne366277:0" + } + ], + "language-support-checked": [ + { + "type": 0, + "value": "crwdns366279:0crwdne366279:0" + } + ], + "language-support-unchecked": [ + { + "type": 0, + "value": "crwdns366281:0crwdne366281:0" + } + ], + "language-supported-for": [ + { + "type": 0, + "value": "crwdns366283:0crwdne366283:0" + } + ], + "language-toast-title": [ + { + "type": 0, + "value": "crwdns366285:0crwdne366285:0" + } + ], "learn-about-firewall-requirements-action": [ { "type": 0, diff --git a/src/messages/ui.nl.json b/src/messages/ui.nl.json index 989c04fdc..5c78a00c2 100644 --- a/src/messages/ui.nl.json +++ b/src/messages/ui.nl.json @@ -1533,6 +1533,42 @@ "value": "Taal" } ], + "language-fully-supported-heading": [ + { + "type": 0, + "value": "Fully supported" + } + ], + "language-partially-supported-heading": [ + { + "type": 0, + "value": "Partially supported" + } + ], + "language-support-checked": [ + { + "type": 0, + "value": "Ondersteund" + } + ], + "language-support-unchecked": [ + { + "type": 0, + "value": "Niet ondersteund" + } + ], + "language-supported-for": [ + { + "type": 0, + "value": "Vertalingen ondersteund voor:" + } + ], + "language-toast-title": [ + { + "type": 0, + "value": "Taal niet volledig ondersteund" + } + ], "learn-about-firewall-requirements-action": [ { "type": 0, diff --git a/src/messages/ui.pl.json b/src/messages/ui.pl.json index c820e1822..bc135e5fb 100644 --- a/src/messages/ui.pl.json +++ b/src/messages/ui.pl.json @@ -1537,6 +1537,42 @@ "value": "Język" } ], + "language-fully-supported-heading": [ + { + "type": 0, + "value": "Fully supported" + } + ], + "language-partially-supported-heading": [ + { + "type": 0, + "value": "Partially supported" + } + ], + "language-support-checked": [ + { + "type": 0, + "value": "Wspierane" + } + ], + "language-support-unchecked": [ + { + "type": 0, + "value": "Niewspierany" + } + ], + "language-supported-for": [ + { + "type": 0, + "value": "Tłumaczenia wspierane dla:" + } + ], + "language-toast-title": [ + { + "type": 0, + "value": "Język nie w pełni obsługiwany" + } + ], "learn-about-firewall-requirements-action": [ { "type": 0, diff --git a/src/messages/ui.pt-br.json b/src/messages/ui.pt-br.json index a3ee8f4c8..056015f3d 100644 --- a/src/messages/ui.pt-br.json +++ b/src/messages/ui.pt-br.json @@ -1533,6 +1533,42 @@ "value": "Idioma" } ], + "language-fully-supported-heading": [ + { + "type": 0, + "value": "Fully supported" + } + ], + "language-partially-supported-heading": [ + { + "type": 0, + "value": "Partially supported" + } + ], + "language-support-checked": [ + { + "type": 0, + "value": "Auxiliado" + } + ], + "language-support-unchecked": [ + { + "type": 0, + "value": "Não auxiliado" + } + ], + "language-supported-for": [ + { + "type": 0, + "value": "Traduções suportadas para:" + } + ], + "language-toast-title": [ + { + "type": 0, + "value": "O idioma possui suporte parcial" + } + ], "learn-about-firewall-requirements-action": [ { "type": 0, diff --git a/src/messages/ui.zh-tw.json b/src/messages/ui.zh-tw.json index a8a5c9465..4f8a95c00 100644 --- a/src/messages/ui.zh-tw.json +++ b/src/messages/ui.zh-tw.json @@ -1529,6 +1529,42 @@ "value": "語言" } ], + "language-fully-supported-heading": [ + { + "type": 0, + "value": "Fully supported" + } + ], + "language-partially-supported-heading": [ + { + "type": 0, + "value": "Partially supported" + } + ], + "language-support-checked": [ + { + "type": 0, + "value": "Supported" + } + ], + "language-support-unchecked": [ + { + "type": 0, + "value": "Unsupported" + } + ], + "language-supported-for": [ + { + "type": 0, + "value": "Translations supported for:" + } + ], + "language-toast-title": [ + { + "type": 0, + "value": "Language not fully supported" + } + ], "learn-about-firewall-requirements-action": [ { "type": 0, diff --git a/src/pages/HomePage.tsx b/src/pages/HomePage.tsx index 27f6d5bab..2b54a50c3 100644 --- a/src/pages/HomePage.tsx +++ b/src/pages/HomePage.tsx @@ -36,8 +36,12 @@ import { userGuideUrl, } from "../utils/external-links"; import { useSettings } from "../store"; +import { useSearchParams } from "react-router-dom"; +import { setEditorVersionOverride } from "../editor-version"; const HomePage = () => { + const [params] = useSearchParams(); + setEditorVersionOverride(params.get("editorVersion") || undefined); const navigate = useNavigate(); const handleGetStarted = useCallback(() => { navigate(createNewPageUrl()); diff --git a/src/pages/ImportPage.tsx b/src/pages/ImportPage.tsx index b1f34509d..18d7aa8a1 100644 --- a/src/pages/ImportPage.tsx +++ b/src/pages/ImportPage.tsx @@ -29,12 +29,14 @@ import { validateProjectName } from "../project-name"; import { useStore } from "../store"; import { createDataSamplesPageUrl } from "../urls"; import { ButtonWithLoading } from "../components/ButtonWithLoading"; +import { setEditorVersionOverride } from "../editor-version"; const ImportPage = () => { const intl = useIntl(); const navigate = useNavigate(); const { activitiesBaseUrl } = useDeployment(); const [params] = useSearchParams(); + setEditorVersionOverride(params.get("editorVersion") || undefined); const defaultProjectName = useDefaultProjectName(); const [name, setName] = useState(defaultProjectName); const isValidSetup = validateProjectName(name); diff --git a/src/settings.tsx b/src/settings.tsx index 697b8b633..b230770b1 100644 --- a/src/settings.tsx +++ b/src/settings.tsx @@ -4,14 +4,16 @@ * * SPDX-License-Identifier: MIT */ -import { stage } from "./environment"; import { DataSamplesView, TourTriggerName } from "./model"; +type Translation = "preview" | boolean; + export interface Language { id: string; name: string; enName: string; - preview?: boolean; + // Language supported in Classroom UI. + ui: Translation; // Language supported in Microsoft MakeCode editor. makeCode: boolean; } @@ -22,54 +24,245 @@ export const allLanguages: Language[] = [ id: "en", name: "English", enName: "English", + ui: true, + makeCode: true, + }, + { + id: "ar", + name: "العربية", + enName: "Arabic", + ui: false, + makeCode: true, + }, + { + id: "bg", + name: "български", + enName: "Bulgarian", + ui: false, makeCode: true, }, { id: "ca", name: "Català", enName: "Catalan", + ui: true, + makeCode: true, + }, + { + id: "cs", + name: "Čeština", + enName: "Czech", + ui: false, + makeCode: true, + }, + { + id: "cy", + name: "Cymraeg", + enName: "Welsh", + ui: false, + makeCode: true, + }, + { + id: "da", + name: "Dansk", + enName: "Danish", + ui: false, + makeCode: true, + }, + { + id: "de", + name: "Deutsch", + enName: "German", + ui: false, + makeCode: true, + }, + { + id: "el", + name: "Ελληνικά", + enName: "Greek", + ui: false, makeCode: true, }, { id: "es-ES", name: "Español", enName: "Spanish", + ui: true, + makeCode: true, + }, + { + id: "fi", + name: "Suomi", + enName: "Finnish", + ui: false, + makeCode: true, + }, + { + id: "fr", + name: "Français", + enName: "French", + ui: false, + makeCode: true, + }, + { + id: "gn", + name: "Avañe'ẽ", + enName: "Guarani", + ui: false, + makeCode: true, + }, + { + id: "he", + name: "עברית", + enName: "Hebrew", + ui: false, + makeCode: true, + }, + { + id: "hu", + name: "Magyar", + enName: "Hungarian", + ui: false, + makeCode: true, + }, + { + id: "is", + name: "Íslenska", + enName: "Icelandic", + ui: false, + makeCode: true, + }, + { + id: "it", + name: "Italiano", + enName: "Italian", + ui: false, makeCode: true, }, { id: "ja", name: "日本語", enName: "Japanese", + ui: true, makeCode: true, }, { id: "ko", name: "한국어", enName: "Korean", + ui: true, makeCode: true, }, { id: "nl", name: "Nederlands", enName: "Dutch", + ui: true, + makeCode: true, + }, + { + id: "nb", + name: "Norsk bokmål", + enName: "Norwegian Bokmal", + ui: false, + makeCode: true, + }, + { + id: "nn-NO", + name: "Norsk nynorsk", + enName: "Norwegian Nynorsk", + ui: false, makeCode: true, }, { id: "pl", name: "Polski", enName: "Polish", + ui: true, makeCode: true, }, { id: "pt-BR", name: "Português (Brasil)", enName: "Portuguese (Brazil)", + ui: true, + makeCode: true, + }, + { + id: "pt-PT", + name: "Português (Portugal)", + enName: "Portuguese (Portugal)", + ui: false, + makeCode: true, + }, + { + id: "ru", + name: "Русский", + enName: "Russian", + ui: false, + makeCode: true, + }, + { + id: "si-LK", + name: "සිංහල", + enName: "Sinhala", + ui: false, + makeCode: true, + }, + { + id: "sk", + name: "Slovenčina", + enName: "Slovak", + ui: false, + makeCode: true, + }, + { + id: "sr", + name: "Srpski", + enName: "Serbian (Latin)", + ui: false, + makeCode: true, + }, + { + id: "sv-SE", + name: "Svenska", + enName: "Swedish", + ui: false, + makeCode: true, + }, + { + id: "tr", + name: "Türkçe", + enName: "Turkish", + ui: false, + makeCode: true, + }, + { + id: "uk", + name: "Українська", + enName: "Ukrainian", + ui: false, + makeCode: true, + }, + { + id: "vi", + name: "Tiếng việt", + enName: "Vietnamese", + ui: false, + makeCode: true, + }, + { + id: "zh-CN", + name: "简体中文", + enName: "Chinese (Simplified)", + ui: false, makeCode: true, }, { id: "zh-TW", name: "繁體中文", enName: "Chinese (Traditional)", + ui: true, makeCode: true, }, ]; @@ -77,15 +270,11 @@ export const allLanguages: Language[] = [ export const getMakeCodeLang = (languageId: string): string => allLanguages.find((l) => l.id === languageId)?.makeCode ? languageId : "en"; -export const supportedLanguages: Language[] = allLanguages.filter( - (l) => stage !== "production" || !l.preview -); - export const getLanguageFromQuery = (): string => { const searchParams = new URLSearchParams(window.location.search); const l = searchParams.get("l"); - const supportedLanguage = supportedLanguages.find((x) => x.id === l); - return supportedLanguage?.id || supportedLanguages[0].id; + const language = allLanguages.find((x) => x.id === l); + return language?.id || allLanguages[0].id; }; export const defaultSettings: Settings = {