i18n: use automatic type inference of translation keys

Finally figured out a way to make typescript strongly type translation
keys so we can avoid the tedium of creating enums of translation keys.
This commit is contained in:
David Lechner
2022-07-22 13:48:50 -05:00
parent 3e10096b6e
commit d6df128860
80 changed files with 402 additions and 875 deletions
+11 -11
View File
@@ -35,7 +35,7 @@ import { useSelector } from '../reducers';
import { useSettingIsShowDocsEnabled } from '../settings/hooks';
import { isMacOS } from '../utils/os';
import { editorActivateFile, editorCloseFile } from './actions';
import { I18nId, useI18n } from './i18n';
import { useI18n } from './i18n';
import * as pybricksMicroPython from './pybricksMicroPython';
import { pybricksMicroPythonId } from './pybricksMicroPython';
import { UntitledHintContribution } from './untitledHint';
@@ -129,9 +129,9 @@ const EditorContextMenu: React.VoidFunctionComponent<EditorContextMenuProps> = (
const canRedo = model && model.canRedo();
return (
<Menu aria-label={i18n.translate(I18nId.ContextMenuLabel)} role="menu">
<Menu aria-label={i18n.translate('contextMenu.label')} role="menu">
<EditorContextMenuItem
label={i18n.translate(I18nId.Copy)}
label={i18n.translate('copy')}
icon="duplicate"
keyboardShortcut={isMacOS() ? 'Cmd-C' : 'Ctrl-C'}
disabled={!hasSelection}
@@ -139,7 +139,7 @@ const EditorContextMenu: React.VoidFunctionComponent<EditorContextMenuProps> = (
editorAction="editor.action.clipboardCopyAction"
/>
<EditorContextMenuItem
label={i18n.translate(I18nId.Paste)}
label={i18n.translate('paste')}
icon="clipboard"
keyboardShortcut={isMacOS() ? 'Cmd-V' : 'Ctrl-V'}
disabled={!model}
@@ -147,7 +147,7 @@ const EditorContextMenu: React.VoidFunctionComponent<EditorContextMenuProps> = (
editorAction="editor.action.clipboardPasteAction"
/>
<EditorContextMenuItem
label={i18n.translate(I18nId.SelectAll)}
label={i18n.translate('selectAll')}
icon="blank"
keyboardShortcut={isMacOS() ? 'Cmd-A' : 'Ctrl-A'}
disabled={!model}
@@ -156,7 +156,7 @@ const EditorContextMenu: React.VoidFunctionComponent<EditorContextMenuProps> = (
/>
<MenuDivider />
<EditorContextMenuItem
label={i18n.translate(I18nId.Undo)}
label={i18n.translate('undo')}
icon="undo"
keyboardShortcut={isMacOS() ? 'Cmd-Z' : 'Ctrl-Z'}
disabled={!canUndo}
@@ -164,7 +164,7 @@ const EditorContextMenu: React.VoidFunctionComponent<EditorContextMenuProps> = (
editorAction="undo"
/>
<EditorContextMenuItem
label={i18n.translate(I18nId.Redo)}
label={i18n.translate('redo')}
icon="redo"
keyboardShortcut={isMacOS() ? 'Cmd-Shift-Z' : 'Ctrl-Shift-Z'}
disabled={!canRedo}
@@ -214,7 +214,7 @@ const TabCloseButton: React.VoidFunctionComponent<TabCloseButtonProps> = ({ uuid
return (
<Button
title={i18n.translate(I18nId.CloseFileTooltip, {
title={i18n.translate('closeFile.tooltip', {
fileName,
})}
minimal={true}
@@ -369,7 +369,7 @@ const Editor: React.VFC = () => {
(editor) => {
const contrib = new UntitledHintContribution(
editor,
i18n.translate(I18nId.Placeholder),
i18n.translate('placeholder'),
);
return () => contrib.dispose();
},
@@ -380,7 +380,7 @@ const Editor: React.VFC = () => {
editor,
() => ({
id: 'pybricks.action.toggleDocs',
label: i18n.translate(I18nId.ToggleDocs),
label: i18n.translate('toggleDocs'),
run: () => toggleIsSettingShowDocsEnabled(),
keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyD],
}),
@@ -391,7 +391,7 @@ const Editor: React.VFC = () => {
editor,
() => ({
id: 'pybricks.action.check',
label: i18n.translate(I18nId.Check),
label: i18n.translate('check'),
run: (e) => {
// for checking, use the most recent compiler
dispatch(compile(e.getValue(), 6, []));
-12
View File
@@ -1,12 +0,0 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2020-2022 The Pybricks Authors
import { lookup } from '../../test';
import { I18nId as I18nId } from './i18n';
import en from './translations/en.json';
describe('Ensure .json file has matches for I18nId', () => {
test.each(Object.values(I18nId))('%s', (id) => {
expect(lookup(en, id)).toBeDefined();
});
});
+5 -18
View File
@@ -1,25 +1,12 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2020-2022 The Pybricks Authors
//
// Editor translation keys.
// Copyright (c) 2022 The Pybricks Authors
import { I18n, useI18n as useShopifyI18n } from '@shopify/react-i18n';
import { useI18n as useShopifyI18n } from '@shopify/react-i18n';
import type { TypedI18n } from '../i18n';
import type translations from './translations/en.json';
export function useI18n(): I18n {
export function useI18n(): TypedI18n<typeof translations> {
// istanbul ignore next: babel-loader rewrites this line
const [i18n] = useShopifyI18n();
return i18n;
}
export enum I18nId {
Placeholder = 'placeholder',
Check = 'check',
ToggleDocs = 'toggleDocs',
Copy = 'copy',
Paste = 'paste',
SelectAll = 'selectAll',
Undo = 'undo',
Redo = 'redo',
CloseFileTooltip = 'closeFile.tooltip',
ContextMenuLabel = 'contextMenu.label',
}