-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Adding new and missing translations for pt-BR and en-US locales, in particular for the new project visibility feature. #3656
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
5250868
97f6d78
b7d6c80
a29a91d
52cfbe7
2845d2f
266974f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -413,7 +413,7 @@ export function deleteProject(id) { | |
}); | ||
}; | ||
} | ||
export function changeVisibility(projectId, projectName, visibility) { | ||
export function changeVisibility(projectId, projectName, visibility, t) { | ||
return (dispatch, getState) => { | ||
const state = getState(); | ||
|
||
|
@@ -443,11 +443,25 @@ export function changeVisibility(projectId, projectName, visibility) { | |
name: response.data.name | ||
}); | ||
|
||
dispatch( | ||
setToastText( | ||
`${projectName} is now ${newVisibility.toLowerCase()}` | ||
) | ||
); | ||
let visibilityLabel; | ||
|
||
switch (newVisibility) { | ||
case 'Public': | ||
visibilityLabel = t('Visibility.Public.Label'); | ||
break; | ||
case 'Private': | ||
visibilityLabel = t('Visibility.Private.Label'); | ||
break; | ||
default: | ||
visibilityLabel = newVisibility; | ||
} | ||
|
||
const visibilityToastText = t('Visibility.Changed', { | ||
projectName, | ||
newVisibility: visibilityLabel.toLowerCase() | ||
}); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This could also be written as:
but as a general rule of thumb introducing locale entries in the source code containing interpolated strings SHOULD BE AVOIDED, since this makes finding unused translations later much harder. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I could see this being adjusted at some point, since we plan to add more visibility options in the future. Maybe there's a way to utilize some kind of dynamic key here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @raclim, I have updated the code to a much more flexible let visibilityLabel;
switch (newVisibility) {
case 'Public':
visibilityLabel = t('Visibility.Public.Label');
break;
case 'Private':
visibilityLabel = t('Visibility.Private.Label');
break;
default:
visibilityLabel = newVisibility;
}
const visibilityToastText = t('Visibility.Changed', {
projectName,
newVisibility: visibilityLabel.toLowerCase()
}); It now becomes much easier to add more visibility options in the future, e.g. a 'Protected' one: switch (newVisibility) {
case 'Public':
visibilityLabel = t('Visibility.Public.Label');
break;
case 'Private':
visibilityLabel = t('Visibility.Private.Label');
break;
case 'Protected':
visibilityLabel = t('Visibility.Protected.Label');
break;
default:
visibilityLabel = newVisibility;
} When using TypeScript (hopefully soon), my suggestion is to futurely create a TS // In some other module.
type VisibilityOptions = 'Public' | 'Private' | 'Protected'
switch (newVisibility) { // `newVisibility` will be of type `VisibilityOptions`
case 'Public':
visibilityLabel = t('Visibility.Public.Label');
break;
case 'Private':
visibilityLabel = t('Visibility.Private.Label');
break;
case 'Protected':
visibilityLabel = t('Visibility.Protected.Label');
break;
default: {
const exhaustiveCheck: never = newVisibility
throw new Error(`Unhandled case: ${exhaustiveCheck}`);
}
} There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Follows another good example where this technique could be used which is, according to my analysis, the only case of a "dynamic" locale key in your entire codebase: export const SkipLink = ({ targetId, text }: SkipLinkProps) => {
// ...
return (
<a
href={`#${targetId}`}
className={linkClasses}
onFocus={handleFocus}
onBlur={handleBlur}
>
{t(`SkipLink.${text}`)}
</a>
);
}; Because, like I mentioned before, interpolating text in order to produce locale keys makes finding them later in the source code an almost impossible task, be it manually or using some automated tool/script. My recommendation would be to replace the above code with a type SkipLinkOptions = 'PlaySketch'; // More could be added later, e.g. 'PlaySketch' | 'StopSketch'
interface SkipLinkProps {
targetId: string;
text: SkipLinkOptions;
}
export const SkipLink = ({ targetId, text }: SkipLinkProps) => {
const [focus, setFocus] = useState(false);
const { t } = useTranslation();
const handleFocus = () => {
setFocus(true);
};
const handleBlur = () => {
setFocus(false);
};
const linkClasses = classNames('skip_link', { focus });
let translatedText: string;
switch (text) {
case 'PlaySketch':
translatedText = t('SkipLink.PlaySketch');
break;
default: {
const exhaustiveCheck: never = text;
throw new Error(`Unhandled case: ${exhaustiveCheck}`);
}
}
return (
<a
href={`#${targetId}`}
className={linkClasses}
onFocus={handleFocus}
onBlur={handleBlur}
>
{translatedText}
</a>
);
}; So, it any new options are added later, but no translations are provided, TS will catch it at compile time: ![]() There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. PS: the above There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks so much for the detailed explanation, I'm still relatively new to TypeScript myself, so this was really helpful! I agree that using union types with exhaustiveness checking would be a great improvement with i18n. I think it could make sense as a follow-up PR if that sounds good! |
||
|
||
dispatch(setToastText(visibilityToastText)); | ||
dispatch(showToast(2000)); | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -29,8 +29,8 @@ | |
"Reference": "Reference", | ||
"About": "About", | ||
"ReportBug": "Report a Bug", | ||
"ChatOnDiscord":"Chat On Discord", | ||
"PostOnTheForum":"Post on the Forum" | ||
"ChatOnDiscord": "Chat On Discord", | ||
"PostOnTheForum": "Post on the Forum" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Notice the missing spaces before the Object values, which were re-introduced automatically by Prettier. |
||
}, | ||
"Lang": "Language", | ||
"BackEditor": "Back to Editor", | ||
|
@@ -690,6 +690,7 @@ | |
"Private": { | ||
"Description": "Only you can see this sketch.", | ||
"Label": "Private" | ||
} | ||
}, | ||
"Changed": "'{{projectName}}' is now {{newVisibility}}..." | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,7 +27,10 @@ | |
"Title": "Ajuda", | ||
"KeyboardShortcuts": "Atalhos de Teclado", | ||
"Reference": "Referência", | ||
"About": "Sobre" | ||
"About": "Sobre", | ||
"ReportBug": "Reportar um Erro", | ||
"ChatOnDiscord": "Conversar no Discord", | ||
"PostOnTheForum": "Postar no Fórum" | ||
}, | ||
"BackEditor": "Voltar ao Editor", | ||
"WarningUnsavedChanges": "Realmente quer sair da página? Há mudanças não salvas.", | ||
|
@@ -208,7 +211,7 @@ | |
"AutocompleteHinterOnARIA": "Geração de dicas do Autocompleter ativada", | ||
"AutocompleteHinterOffARIA": "Geração de dicas do Autocompleter desativada", | ||
"LibraryVersion": "Versão do p5.js", | ||
"LibraryVersionInfo": "Há uma [nova versão 2.0](https://github.com/processing/p5.js/releases/) do p5.js disponível! Ela se tornará padrão em agosto de 2026, então aproveite este tempo para testá-la e relatar bugs. Está interessado em transitar esboços de 1.x para 2.0? Confira os [recursos de compatibilidade e transição.](https://github.com/processing/p5.js-compatibility)", | ||
"LibraryVersionInfo": "Há uma [nova versão 2.0](https://github.com/processing/p5.js/releases/) do p5.js disponível! Ela se tornará padrão em agosto de 2026, então aproveite este tempo para testá-la e relatar erros. Está interessado em migrar esboços de 1.x para 2.0? Confira os [recursos de compatibilidade e migração.](https://github.com/processing/p5.js-compatibility)", | ||
"CustomVersionTitle": "Gerenciando suas próprias bibliotecas? Legal!", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have used the proper pt-BR verb here ("migrar" instead of "transitar"). |
||
"CustomVersionInfo": "A versão do p5.js está atualmente sendo gerenciada no código do index.html. Isso significa que não pode ser ajustada a partir desta aba.", | ||
"CustomVersionReset": "Se você gostaria de usar as bibliotecas padrão, pode substituir as tags de script no index.html pelo seguinte:", | ||
|
@@ -621,6 +624,7 @@ | |
"Private": { | ||
"Description": "Apenas você pode ver este esboço.", | ||
"Label": "Privado" | ||
} | ||
}, | ||
"Changed": "'{{projectName}}' agora é {{newVisibility}}..." | ||
} | ||
} |
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Renaming menu entry to "Português do Brasil", in order to distinguish it from Portuguese of Portugal.