mirror of
https://github.com/pybricks/pybricks-code.git
synced 2026-09-14 10:35:11 +00:00
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:
@@ -4,14 +4,14 @@
|
||||
import { Intent } from '@blueprintjs/core';
|
||||
import React from 'react';
|
||||
import { CreateToast } from '../../i18nToaster';
|
||||
import { I18nId, useI18n } from './i18n';
|
||||
import { useI18n } from './i18n';
|
||||
|
||||
const BluetoothNotAvailable: React.VoidFunctionComponent = () => {
|
||||
const i18n = useI18n();
|
||||
return (
|
||||
<>
|
||||
<p>{i18n.translate(I18nId.BluetoothNotAvailableMessage)}</p>
|
||||
<p>{i18n.translate(I18nId.BluetoothNotAvailableSuggestion)}</p>
|
||||
<p>{i18n.translate('bluetoothNotAvailable.message')}</p>
|
||||
<p>{i18n.translate('bluetoothNotAvailable.suggestion')}</p>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
import { Intent } from '@blueprintjs/core';
|
||||
import React from 'react';
|
||||
import { CreateToast } from '../../i18nToaster';
|
||||
import { I18nId, useI18n } from './i18n';
|
||||
import { useI18n } from './i18n';
|
||||
|
||||
type MissingServiceProps = {
|
||||
serviceName: string;
|
||||
@@ -18,9 +18,9 @@ const MissingService: React.VoidFunctionComponent<MissingServiceProps> = ({
|
||||
const i18n = useI18n();
|
||||
return (
|
||||
<>
|
||||
<p>{i18n.translate(I18nId.MissingServiceMessage, { serviceName })}</p>
|
||||
<p>{i18n.translate(I18nId.MissingServiceSuggestion1)}</p>
|
||||
<p>{i18n.translate(I18nId.MissingServiceSuggestion2, { hubName })}</p>
|
||||
<p>{i18n.translate('missingService.message', { serviceName })}</p>
|
||||
<p>{i18n.translate('missingService.suggestion1')}</p>
|
||||
<p>{i18n.translate('missingService.suggestion2', { hubName })}</p>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
import { Intent } from '@blueprintjs/core';
|
||||
import React from 'react';
|
||||
import { CreateToast } from '../../i18nToaster';
|
||||
import { I18nId, useI18n } from './i18n';
|
||||
import { useI18n } from './i18n';
|
||||
|
||||
const NoGatt: React.VoidFunctionComponent = () => {
|
||||
const i18n = useI18n();
|
||||
return <p>{i18n.translate(I18nId.NoGattMessage)}</p>;
|
||||
return <p>{i18n.translate('noGatt.message')}</p>;
|
||||
};
|
||||
|
||||
export const noGatt: CreateToast = (onAction) => {
|
||||
|
||||
@@ -7,7 +7,7 @@ import React from 'react';
|
||||
import { appName, pybricksBluetoothTroubleshootingUrl } from '../../app/constants';
|
||||
import { CreateToast } from '../../i18nToaster';
|
||||
import ExternalLinkIcon from '../../utils/ExternalLinkIcon';
|
||||
import { I18nId, useI18n } from './i18n';
|
||||
import { useI18n } from './i18n';
|
||||
|
||||
type NoHubProps = {
|
||||
onFlashFirmware: () => void;
|
||||
@@ -18,28 +18,26 @@ const NoHub: React.VoidFunctionComponent<NoHubProps> = ({ onFlashFirmware }) =>
|
||||
|
||||
return (
|
||||
<>
|
||||
<p>{i18n.translate(I18nId.NoHubMessage)}</p>
|
||||
<p>{i18n.translate('noHub.message')}</p>
|
||||
<p>
|
||||
{i18n.translate(I18nId.NoHubSuggestion1, {
|
||||
{i18n.translate('noHub.suggestion1', {
|
||||
appName,
|
||||
buttonName: (
|
||||
<strong>
|
||||
{i18n.translate(I18nId.NoHubFlashFirmwareButton)}
|
||||
</strong>
|
||||
<strong>{i18n.translate('noHub.flashFirmwareButton')}</strong>
|
||||
),
|
||||
})}
|
||||
</p>
|
||||
<p>{i18n.translate(I18nId.NoHubSuggestion2)}</p>
|
||||
<p>{i18n.translate('noHub.suggestion2')}</p>
|
||||
<div className="pb-ble-alerts-buttons">
|
||||
<Button icon="download" onClick={onFlashFirmware}>
|
||||
{i18n.translate(I18nId.NoHubFlashFirmwareButton)}
|
||||
{i18n.translate('noHub.flashFirmwareButton')}
|
||||
</Button>
|
||||
<AnchorButton
|
||||
icon="help"
|
||||
href={pybricksBluetoothTroubleshootingUrl}
|
||||
target="_blank"
|
||||
>
|
||||
{i18n.translate(I18nId.NoHubTroubleshootButton)}
|
||||
{i18n.translate('noHub.troubleshootButton')}
|
||||
<ExternalLinkIcon />
|
||||
</AnchorButton>
|
||||
</div>
|
||||
|
||||
@@ -5,19 +5,19 @@ import { Button, Intent } from '@blueprintjs/core';
|
||||
import React from 'react';
|
||||
import { CreateToast } from '../../i18nToaster';
|
||||
import { isIOS, isLinux } from '../../utils/os';
|
||||
import { I18nId, useI18n } from './i18n';
|
||||
import { useI18n } from './i18n';
|
||||
|
||||
const NoWebBluetooth: React.VoidFunctionComponent = () => {
|
||||
const i18n = useI18n();
|
||||
return (
|
||||
<>
|
||||
<p>{i18n.translate(I18nId.NoWebBluetoothMessage)}</p>
|
||||
<p>{i18n.translate('noWebBluetooth.message')}</p>
|
||||
{!isLinux() && !isIOS() && (
|
||||
<p>{i18n.translate(I18nId.NoWebBluetoothSuggestion)}</p>
|
||||
<p>{i18n.translate('noWebBluetooth.suggestion')}</p>
|
||||
)}
|
||||
{isLinux() && (
|
||||
<>
|
||||
<p>{i18n.translate(I18nId.NoWebBluetoothLinux)}</p>
|
||||
<p>{i18n.translate('noWebBluetooth.linux')}</p>
|
||||
<p>
|
||||
<code>
|
||||
chrome://flags/#enable-experimental-web-platform-features
|
||||
|
||||
@@ -5,7 +5,7 @@ import './index.scss';
|
||||
import { Button, Intent } from '@blueprintjs/core';
|
||||
import React from 'react';
|
||||
import { CreateToast } from '../../i18nToaster';
|
||||
import { I18nId, useI18n } from './i18n';
|
||||
import { useI18n } from './i18n';
|
||||
|
||||
type OldFirmwareProps = {
|
||||
onFlashFirmware: () => void;
|
||||
@@ -18,10 +18,10 @@ const OldFirmware: React.VoidFunctionComponent<OldFirmwareProps> = ({
|
||||
|
||||
return (
|
||||
<>
|
||||
<p>{i18n.translate(I18nId.OldFirmwareMessage)}</p>
|
||||
<p>{i18n.translate('oldFirmware.message')}</p>
|
||||
<div className="pb-ble-alerts-buttons">
|
||||
<Button icon="download" onClick={onFlashFirmware}>
|
||||
{i18n.translate(I18nId.OldFirmwareFlashFirmwareLabel)}
|
||||
{i18n.translate('oldFirmware.flashFirmware.label')}
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2022 The Pybricks Authors
|
||||
|
||||
import { lookup } from '../../../test';
|
||||
import { 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();
|
||||
});
|
||||
});
|
||||
+4
-21
@@ -1,29 +1,12 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// 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 {
|
||||
NoWebBluetoothMessage = 'noWebBluetooth.message',
|
||||
NoWebBluetoothSuggestion = 'noWebBluetooth.suggestion',
|
||||
NoWebBluetoothLinux = 'noWebBluetooth.linux',
|
||||
BluetoothNotAvailableMessage = 'bluetoothNotAvailable.message',
|
||||
BluetoothNotAvailableSuggestion = 'bluetoothNotAvailable.suggestion',
|
||||
NoGattMessage = 'noGatt.message',
|
||||
MissingServiceMessage = 'missingService.message',
|
||||
MissingServiceSuggestion1 = 'missingService.suggestion1',
|
||||
MissingServiceSuggestion2 = 'missingService.suggestion2',
|
||||
NoHubMessage = 'noHub.message',
|
||||
NoHubSuggestion1 = 'noHub.suggestion1',
|
||||
NoHubSuggestion2 = 'noHub.suggestion2',
|
||||
NoHubFlashFirmwareButton = 'noHub.flashFirmwareButton',
|
||||
NoHubTroubleshootButton = 'noHub.troubleshootButton',
|
||||
OldFirmwareMessage = 'oldFirmware.message',
|
||||
OldFirmwareFlashFirmwareLabel = 'oldFirmware.flashFirmware.label',
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user