From 04da737bbf4f30d7a3976d4dccf45f73d7d1018f Mon Sep 17 00:00:00 2001 From: Deveshi Dwivedi Date: Thu, 22 May 2025 10:53:56 +0530 Subject: [PATCH 1/9] feat: detect and use browser language as default for first-time users --- client/i18n.js | 19 +++- client/modules/IDE/reducers/preferences.js | 3 +- client/utils/language-utils.js | 107 +++++++++++++++++++++ 3 files changed, 127 insertions(+), 2 deletions(-) create mode 100644 client/utils/language-utils.js diff --git a/client/i18n.js b/client/i18n.js index 722e3856a5..25ce8f19d9 100644 --- a/client/i18n.js +++ b/client/i18n.js @@ -21,6 +21,8 @@ import { enIN } from 'date-fns/locale'; +import getPreferredLanguage from './utils/language-utils'; + const fallbackLng = ['en-US']; export const availableLanguages = [ @@ -42,6 +44,21 @@ export const availableLanguages = [ 'ur' ]; +const detectedLanguage = getPreferredLanguage( + availableLanguages, + fallbackLng[0] +); + +let initialLanguage = detectedLanguage; + +// if user has a saved preference (e.g., from redux or window.__INITIAL_STATE__), use that +if ( + window.__INITIAL_STATE__?.preferences?.language && + availableLanguages.includes(window.__INITIAL_STATE__.preferences.language) +) { + initialLanguage = window.__INITIAL_STATE__.preferences.language; +} + export function languageKeyToLabel(lang) { const languageMap = { be: 'বাংলা', @@ -104,7 +121,7 @@ i18n // .use(LanguageDetector)// to detect the language from currentBrowser .use(Backend) // to fetch the data from server .init({ - lng: 'en-US', + lng: initialLanguage, fallbackLng, // if user computer language is not on the list of available languages, than we will be using the fallback language specified earlier debug: false, backend: options, diff --git a/client/modules/IDE/reducers/preferences.js b/client/modules/IDE/reducers/preferences.js index 630fa465ef..d6323c4fd2 100644 --- a/client/modules/IDE/reducers/preferences.js +++ b/client/modules/IDE/reducers/preferences.js @@ -1,4 +1,5 @@ import * as ActionTypes from '../../../constants'; +import i18n from '../../../i18n'; export const initialState = { tabIndex: 0, @@ -11,7 +12,7 @@ export const initialState = { gridOutput: false, theme: 'light', autorefresh: false, - language: 'en-US', + language: i18n.language, autocloseBracketsQuotes: true, autocompleteHinter: false }; diff --git a/client/utils/language-utils.js b/client/utils/language-utils.js new file mode 100644 index 0000000000..306cabbc3e --- /dev/null +++ b/client/utils/language-utils.js @@ -0,0 +1,107 @@ +/** + * Utility functions for language detection and handling + */ + +function detectLanguageFromUserAgent(userAgent) { + const langRegexes = [ + /\b([a-z]{2}(-[A-Z]{2})?);/i, // matches patterns like "en;" or "en-US;" + /\[([a-z]{2}(-[A-Z]{2})?)\]/i // matches patterns like "[en]" or "[en-US]" + ]; + + const match = langRegexes.reduce((result, regex) => { + if (result) return result; + const matches = userAgent.match(regex); + return matches && matches[1] ? matches[1] : null; + }, null); + + return match; +} + +function getPreferredLanguage(supportedLanguages = [], defaultLanguage = 'en') { + if (typeof navigator === 'undefined') { + return defaultLanguage; + } + + const normalizeLanguage = (langCode) => langCode.toLowerCase().trim(); + + const normalizedSupported = supportedLanguages.map(normalizeLanguage); + + if (navigator.languages && navigator.languages.length) { + const matchedLang = navigator.languages.find((browserLang) => { + const normalizedBrowserLang = normalizeLanguage(browserLang); + + const hasExactMatch = + normalizedSupported.findIndex( + (lang) => lang === normalizedBrowserLang + ) !== -1; + + if (hasExactMatch) { + return true; + } + + const languageOnly = normalizedBrowserLang.split('-')[0]; + const hasLanguageOnlyMatch = + normalizedSupported.findIndex( + (lang) => lang === languageOnly || lang.startsWith(`${languageOnly}-`) + ) !== -1; + + return hasLanguageOnlyMatch; + }); + + if (matchedLang) { + const normalizedMatchedLang = normalizeLanguage(matchedLang); + const exactMatchIndex = normalizedSupported.findIndex( + (lang) => lang === normalizedMatchedLang + ); + + if (exactMatchIndex !== -1) { + return supportedLanguages[exactMatchIndex]; + } + + const languageOnly = normalizedMatchedLang.split('-')[0]; + const languageOnlyMatchIndex = normalizedSupported.findIndex( + (lang) => lang === languageOnly || lang.startsWith(`${languageOnly}-`) + ); + + if (languageOnlyMatchIndex !== -1) { + return supportedLanguages[languageOnlyMatchIndex]; + } + } + } + + if (navigator.language) { + const normalizedNavLang = normalizeLanguage(navigator.language); + const exactMatchIndex = normalizedSupported.findIndex( + (lang) => lang === normalizedNavLang + ); + + if (exactMatchIndex !== -1) { + return supportedLanguages[exactMatchIndex]; + } + + const languageOnly = normalizedNavLang.split('-')[0]; + const languageOnlyMatchIndex = normalizedSupported.findIndex( + (lang) => lang === languageOnly || lang.startsWith(`${languageOnly}-`) + ); + + if (languageOnlyMatchIndex !== -1) { + return supportedLanguages[languageOnlyMatchIndex]; + } + } + + if (navigator.userAgent) { + const userAgentLang = detectLanguageFromUserAgent(navigator.userAgent); + if ( + userAgentLang && + normalizedSupported.includes(normalizeLanguage(userAgentLang)) + ) { + const index = normalizedSupported.indexOf( + normalizeLanguage(userAgentLang) + ); + return supportedLanguages[index]; + } + } + return defaultLanguage; +} + +export default getPreferredLanguage; From e5dc04dc75fd818f7013fc58d060563b10110cd2 Mon Sep 17 00:00:00 2001 From: Deveshi Dwivedi Date: Wed, 28 May 2025 12:55:35 +0530 Subject: [PATCH 2/9] refactor: remove userAgent language detection --- client/utils/language-utils.js | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/client/utils/language-utils.js b/client/utils/language-utils.js index 306cabbc3e..b173a3137f 100644 --- a/client/utils/language-utils.js +++ b/client/utils/language-utils.js @@ -2,21 +2,6 @@ * Utility functions for language detection and handling */ -function detectLanguageFromUserAgent(userAgent) { - const langRegexes = [ - /\b([a-z]{2}(-[A-Z]{2})?);/i, // matches patterns like "en;" or "en-US;" - /\[([a-z]{2}(-[A-Z]{2})?)\]/i // matches patterns like "[en]" or "[en-US]" - ]; - - const match = langRegexes.reduce((result, regex) => { - if (result) return result; - const matches = userAgent.match(regex); - return matches && matches[1] ? matches[1] : null; - }, null); - - return match; -} - function getPreferredLanguage(supportedLanguages = [], defaultLanguage = 'en') { if (typeof navigator === 'undefined') { return defaultLanguage; @@ -89,18 +74,6 @@ function getPreferredLanguage(supportedLanguages = [], defaultLanguage = 'en') { } } - if (navigator.userAgent) { - const userAgentLang = detectLanguageFromUserAgent(navigator.userAgent); - if ( - userAgentLang && - normalizedSupported.includes(normalizeLanguage(userAgentLang)) - ) { - const index = normalizedSupported.indexOf( - normalizeLanguage(userAgentLang) - ); - return supportedLanguages[index]; - } - } return defaultLanguage; } From 96684b7aa5fb085e732372e07e02b74163149c62 Mon Sep 17 00:00:00 2001 From: Yugal Kaushik Date: Sun, 1 Jun 2025 22:17:04 +0530 Subject: [PATCH 3/9] Fix broken link for preparing an issue --- .github/CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 2af5a6d239..6d0fc6757c 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -53,7 +53,7 @@ Issues with these labels are a great place to start! - [Need Steps to Reproduce](https://github.com/processing/p5.js-web-editor/labels/Needs%20Steps%20to%20Reproduce) - [Ready for Work](https://github.com/processing/p5.js-web-editor/labels/Ready%20for%20Work) -A breakdown of what each label means can be found in the [Preparing an Issue Guide](#preparing-an-issue). +A breakdown of what each label means can be found in the [Preparing an Issue Guide](../contributor_docs/preparing_an_issue.md). When approaching these issues, know that it's okay to not know how to fix an issue! Feel free to ask questions about to approach the problem. We are all here to learn and make something awesome. Someone from the community will help you out, and asking questions is a great way to learn about the p5.js editor, its file structure, and development process. From b915a196cc0114eef1ed172b28acc3f62162c7a0 Mon Sep 17 00:00:00 2001 From: Yugal Kaushik Date: Mon, 2 Jun 2025 09:25:49 +0530 Subject: [PATCH 4/9] Fix broken link for preparing an issue --- .github/CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 6d0fc6757c..01d1f4abad 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -83,7 +83,7 @@ Before submitting a pull request, make sure that: --- ## Ideas for Getting Started -* Use the [p5.js Editor](https://editor.p5js.org)! Find a bug? Think of something you think would add to the project? Reference the [Preparing an Issue Guide](#preparing-an-issue) and open an issue. +* Use the [p5.js Editor](https://editor.p5js.org)! Find a bug? Think of something you think would add to the project? Reference the [Preparing an Issue Guide](../contributor_docs/preparing_an_issue.md) and open an issue. * Expand an existing issue. Sometimes issues are missing steps to reproduce, or need suggestions for potential solutions. Sometimes they need another voice saying, "this is really important!" * Try getting the project running locally on your computer by following the [installation steps](./../contributor_docs/installation.md). * Look through the documentation in the [developer docs](../contributor_docs/) and the [development guide](./../contributor_docs/development.md). Is there anything that could be expanded? Is there anything missing? From 49da364719b172becc461bd995d88b38f6ee30e8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 Jun 2025 06:16:58 +0000 Subject: [PATCH 5/9] Bump tar-fs from 2.1.2 to 2.1.3 Bumps [tar-fs](https://github.com/mafintosh/tar-fs) from 2.1.2 to 2.1.3. - [Commits](https://github.com/mafintosh/tar-fs/commits) --- updated-dependencies: - dependency-name: tar-fs dependency-version: 2.1.3 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- package-lock.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index f8748acd7e..86de2a8c0e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -38398,9 +38398,9 @@ } }, "node_modules/tar-fs": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.2.tgz", - "integrity": "sha512-EsaAXwxmx8UB7FRKqeozqEPop69DXcmYwTQwXvyAPF352HJsPdkVhvTaDPYqfNgruveJIJy3TA2l+2zj8LJIJA==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.3.tgz", + "integrity": "sha512-090nwYJDmlhwFwEW3QQl+vaNnxsO2yVsd45eTKRBzSzu+hlb1w2K9inVq5b0ngXuLVqQ4ApvsUHHnu/zQNkWAg==", "dev": true, "license": "MIT", "dependencies": { @@ -69013,9 +69013,9 @@ } }, "tar-fs": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.2.tgz", - "integrity": "sha512-EsaAXwxmx8UB7FRKqeozqEPop69DXcmYwTQwXvyAPF352HJsPdkVhvTaDPYqfNgruveJIJy3TA2l+2zj8LJIJA==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.3.tgz", + "integrity": "sha512-090nwYJDmlhwFwEW3QQl+vaNnxsO2yVsd45eTKRBzSzu+hlb1w2K9inVq5b0ngXuLVqQ4ApvsUHHnu/zQNkWAg==", "dev": true, "requires": { "chownr": "^1.1.1", From cd85ce91d6af838a95137090b917fee873cfe965 Mon Sep 17 00:00:00 2001 From: Yugal Kaushik Date: Tue, 3 Jun 2025 12:38:49 +0530 Subject: [PATCH 6/9] Improve account section terminology and labels --- client/modules/IDE/components/Header/Nav.jsx | 2 +- client/modules/User/components/AccountForm.jsx | 2 +- translations/locales/en-US/translations.json | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/client/modules/IDE/components/Header/Nav.jsx b/client/modules/IDE/components/Header/Nav.jsx index 2ed8dd224e..151e2d8212 100644 --- a/client/modules/IDE/components/Header/Nav.jsx +++ b/client/modules/IDE/components/Header/Nav.jsx @@ -378,7 +378,7 @@ const AuthenticatedUserMenu = () => { {t('Nav.Auth.MyAssets')} - {t('Preferences.Settings')} + {t('Nav.Auth.MyAccount')} dispatch(logoutUser())}> {t('Nav.Auth.LogOut')} diff --git a/client/modules/User/components/AccountForm.jsx b/client/modules/User/components/AccountForm.jsx index f2f10ec6d5..4406d58c17 100644 --- a/client/modules/User/components/AccountForm.jsx +++ b/client/modules/User/components/AccountForm.jsx @@ -176,7 +176,7 @@ function AccountForm() { )} )} diff --git a/translations/locales/en-US/translations.json b/translations/locales/en-US/translations.json index 376c18471c..afbb6e5057 100644 --- a/translations/locales/en-US/translations.json +++ b/translations/locales/en-US/translations.json @@ -367,13 +367,13 @@ "CurrentPasswordARIA": "Current Password", "NewPassword": "New Password", "NewPasswordARIA": "New Password", - "SubmitSaveAllSettings": "Save All Settings" + "SaveAccountDetails": "Save Account Details" }, "AccountView": { "SocialLogin": "Social Login", "SocialLoginDescription": "Use your GitHub or Google account to log into the p5.js Web Editor.", "Title": "p5.js Web Editor | Account Settings", - "Settings": "Account Settings", + "Settings": "My Account", "AccountTab": "Account", "AccessTokensTab": "Access Tokens" }, From b8e1895b3d4c581d56f085585c8666e35a450d36 Mon Sep 17 00:00:00 2001 From: Yugal Kaushik Date: Tue, 3 Jun 2025 12:58:12 +0530 Subject: [PATCH 7/9] Update AccountForum submit button test --- .../User/components/AccountForm.unit.test.jsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/client/modules/User/components/AccountForm.unit.test.jsx b/client/modules/User/components/AccountForm.unit.test.jsx index 653dce5243..caaa7ddc39 100644 --- a/client/modules/User/components/AccountForm.unit.test.jsx +++ b/client/modules/User/components/AccountForm.unit.test.jsx @@ -61,8 +61,8 @@ describe('', () => { it('handles form submission and calls updateSettings', async () => { subject(); - const saveAllSettingsButton = screen.getByRole('button', { - name: /save all settings/i + const saveAccountDetailsButton = screen.getByRole('button', { + name: /save account details/i }); const currentPasswordElement = screen.getByLabelText(/current password/i); @@ -81,7 +81,7 @@ describe('', () => { }); await act(async () => { - fireEvent.click(saveAllSettingsButton); + fireEvent.click(saveAccountDetailsButton); }); await waitFor(() => { @@ -92,8 +92,8 @@ describe('', () => { it('Save all setting button should get disabled while submitting and enable when not submitting', async () => { subject(); - const saveAllSettingsButton = screen.getByRole('button', { - name: /save all settings/i + const saveAccountDetailsButton = screen.getByRole('button', { + name: /save account details/i }); const currentPasswordElement = screen.getByLabelText(/current password/i); @@ -110,12 +110,12 @@ describe('', () => { value: 'newPassword' } }); - expect(saveAllSettingsButton).not.toHaveAttribute('disabled'); + expect(saveAccountDetailsButton).not.toHaveAttribute('disabled'); await act(async () => { - fireEvent.click(saveAllSettingsButton); + fireEvent.click(saveAccountDetailsButton); await waitFor(() => { - expect(saveAllSettingsButton).toHaveAttribute('disabled'); + expect(saveAccountDetailsButton).toHaveAttribute('disabled'); }); }); }); From 961f038e176845239233c5fff2ad69fedce14121 Mon Sep 17 00:00:00 2001 From: kit <1304340+ksen0@users.noreply.github.com> Date: Mon, 9 Jun 2025 09:57:45 +0200 Subject: [PATCH 8/9] Update useP5Version.jsx to include 1.11.8 patch --- client/modules/IDE/hooks/useP5Version.jsx | 1 + 1 file changed, 1 insertion(+) diff --git a/client/modules/IDE/hooks/useP5Version.jsx b/client/modules/IDE/hooks/useP5Version.jsx index 6f38eac625..03ba3d0da4 100644 --- a/client/modules/IDE/hooks/useP5Version.jsx +++ b/client/modules/IDE/hooks/useP5Version.jsx @@ -12,6 +12,7 @@ export const p5Versions = [ '2.0.2', '2.0.1', '2.0.0', + '1.11.8', '1.11.7', '1.11.6', '1.11.5', From 07a99fe443fd1f4483cf2604810b0bf99f60d045 Mon Sep 17 00:00:00 2001 From: raclim <43053081+raclim@users.noreply.github.com> Date: Mon, 9 Jun 2025 20:21:02 -0400 Subject: [PATCH 9/9] 2.16.6 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 86de2a8c0e..6791d00abf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "p5.js-web-editor", - "version": "2.16.5", + "version": "2.16.6", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "p5.js-web-editor", - "version": "2.16.5", + "version": "2.16.6", "license": "LGPL-2.1", "dependencies": { "@auth0/s3": "^1.0.0", diff --git a/package.json b/package.json index 2f0293e1fc..21f23d7336 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "p5.js-web-editor", - "version": "2.16.5", + "version": "2.16.6", "description": "The web editor for p5.js.", "scripts": { "clean": "rimraf dist",