Skip to content

feat: finalize basic i18n support #133

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

Merged
merged 5 commits into from
Jul 12, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions packages/astro/src/default/utils/content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ export async function getTutorial(): Promise<Tutorial> {
noPreviewNorStepsText: 'No preview to run nor steps to show',
startWebContainerText: 'Run this tutorial',
editPageText: 'Edit this page',
filesTitleText: 'Files',
prepareEnvironmentTitleText: 'Preparing Environment',
toggleTerminalButtonText: 'Toggle Terminal',
solveButtonText: 'Solve',
resetButtonText: 'Reset',
} satisfies Lesson['data']['i18n'],
tutorialMetaData.i18n,
);
Expand Down
4 changes: 2 additions & 2 deletions packages/astro/src/default/utils/content/squash.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ describe('squash', () => {
data: {
template: 'default',
i18n: {
nextLessonPrefix: 'Next lesson: ',
startWebContainerText: 'Run this tutorial',
partTemplate: 'Part ${index}: ${title}',
},
} satisfies Metadata,
Expand All @@ -107,7 +107,7 @@ describe('squash', () => {

expect(squash<Metadata>([lesson1.data, tutorial.data], ['i18n'])).toEqual({
i18n: {
nextLessonPrefix: 'Next lesson: ',
startWebContainerText: 'Run this tutorial',
partTemplate: 'Foobar: ${title}',
},
});
Expand Down
16 changes: 10 additions & 6 deletions packages/components/react/src/Panels/EditorPanel.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { I18n } from '@tutorialkit/types';
import { useEffect, useRef } from 'react';
import { Panel, PanelGroup, PanelResizeHandle, type ImperativePanelHandle } from 'react-resizable-panels';
import {
Expand All @@ -7,8 +8,8 @@ import {
type OnScrollCallback as OnEditorScroll,
} from '../core/CodeMirrorEditor/index.js';
import { FileTree } from '../core/FileTree.js';
import resizePanelStyles from '../styles/resize-panel.module.css';
import type { Theme } from '../core/types.js';
import resizePanelStyles from '../styles/resize-panel.module.css';
import { isMobile } from '../utils/mobile.js';

const DEFAULT_FILE_TREE_SIZE = 25;
Expand All @@ -17,6 +18,7 @@ interface Props {
theme: Theme;
id: unknown;
files: string[];
i18n: I18n;
hideRoot?: boolean;
fileTreeScope?: string;
showFileTree?: boolean;
Expand All @@ -33,6 +35,7 @@ export function EditorPanel({
theme,
id,
files,
i18n,
hideRoot,
fileTreeScope,
showFileTree = true,
Expand Down Expand Up @@ -68,7 +71,7 @@ export function EditorPanel({
<div className="panel-header border-r border-b border-tk-elements-app-borderColor">
<div className="panel-title">
<div className="panel-icon i-ph-tree-structure-duotone shrink-0"></div>
<span className="text-sm">Files</span>
<span className="text-sm">{i18n.filesTitleText}</span>
</div>
</div>
<FileTree
Expand All @@ -86,7 +89,7 @@ export function EditorPanel({
hitAreaMargins={{ fine: 8, coarse: 8 }}
/>
<Panel className="flex flex-col" defaultSize={100} minSize={10}>
<FileTab editorDocument={editorDocument} onHelpClick={onHelpClick} helpAction={helpAction} />
<FileTab i18n={i18n} editorDocument={editorDocument} onHelpClick={onHelpClick} helpAction={helpAction} />
<div className="h-full flex-1 overflow-hidden">
<CodeMirrorEditor
className="h-full"
Expand All @@ -104,12 +107,13 @@ export function EditorPanel({
}

interface FileTabProps {
i18n: I18n;
editorDocument: EditorDocument | undefined;
helpAction?: 'reset' | 'solve';
onHelpClick?: () => void;
}

function FileTab({ editorDocument, helpAction, onHelpClick }: FileTabProps) {
function FileTab({ i18n, editorDocument, helpAction, onHelpClick }: FileTabProps) {
const filePath = editorDocument?.filePath;
const fileName = filePath?.split('/').at(-1) ?? '';
const icon = fileName ? getFileIcon(fileName) : '';
Expand All @@ -123,9 +127,9 @@ function FileTab({ editorDocument, helpAction, onHelpClick }: FileTabProps) {
{!!helpAction && (
<button onClick={onHelpClick} className="panel-button px-2 py-0.5 -mr-1 -my-1">
{helpAction === 'solve' && <div className="i-ph-lightbulb-duotone text-lg" />}
{helpAction === 'solve' && 'Solve'}
{helpAction === 'solve' && i18n.solveButtonText}
{helpAction === 'reset' && <div className="i-ph-clock-counter-clockwise-duotone" />}
{helpAction === 'reset' && 'Reset'}
{helpAction === 'reset' && i18n.resetButtonText}
</button>
)}
</div>
Expand Down
8 changes: 5 additions & 3 deletions packages/components/react/src/Panels/PreviewPanel.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useStore } from '@nanostores/react';
import type { PreviewInfo, TutorialStore } from '@tutorialkit/runtime';
import type { I18n } from '@tutorialkit/types';
import { createElement, forwardRef, memo, useCallback, useEffect, useImperativeHandle, useRef } from 'react';
import { Panel, PanelGroup, PanelResizeHandle } from 'react-resizable-panels';
import { BootScreen } from '../BootScreen.js';
Expand All @@ -10,6 +11,7 @@ interface Props {
showToggleTerminal?: boolean;
toggleTerminal?: () => void;
tutorialStore: TutorialStore;
i18n: I18n;
}

const previewsContainer = globalThis.document ? document.getElementById('previews-container')! : ({} as HTMLElement);
Expand All @@ -21,7 +23,7 @@ export type ImperativePreviewHandle = {
};

export const PreviewPanel = memo(
forwardRef<ImperativePreviewHandle, Props>(({ showToggleTerminal, toggleTerminal, tutorialStore }, ref) => {
forwardRef<ImperativePreviewHandle, Props>(({ showToggleTerminal, toggleTerminal, i18n, tutorialStore }, ref) => {
const expectedPreviews = useStore(tutorialStore.previews);
const iframeRefs = useRef<IFrameRef[]>([]);

Expand Down Expand Up @@ -86,7 +88,7 @@ export const PreviewPanel = memo(
<div className="panel-header border-b border-tk-elements-app-borderColor justify-between">
<div className="panel-title">
<div className="panel-icon i-ph-lightning-duotone"></div>
<span className="text-sm">Preparing Environment</span>
<span className="text-sm">{i18n.prepareEnvironmentTitleText}</span>
</div>
{showToggleTerminal && (
<button
Expand All @@ -95,7 +97,7 @@ export const PreviewPanel = memo(
onClick={() => toggleTerminal?.()}
>
<span className="panel-button-icon i-ph-terminal-window-duotone"></span>
<span className="text-sm">Toggle Terminal</span>
<span className="text-sm">{i18n.toggleTerminalButtonText}</span>
</button>
)}
</div>
Expand Down
9 changes: 6 additions & 3 deletions packages/components/react/src/Panels/WorkspacePanel.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import { useStore } from '@nanostores/react';
import { TutorialStore } from '@tutorialkit/runtime';
import type { I18n } from '@tutorialkit/types';
import { useCallback, useEffect, useRef, useState } from 'react';
import { useStore } from '@nanostores/react';
import { Panel, PanelGroup, PanelResizeHandle, type ImperativePanelHandle } from 'react-resizable-panels';
import type {
OnChangeCallback as OnEditorChange,
OnScrollCallback as OnEditorScroll,
} from '../core/CodeMirrorEditor/index.js';
import resizePanelStyles from '../styles/resize-panel.module.css';
import type { Theme } from '../core/types.js';
import resizePanelStyles from '../styles/resize-panel.module.css';
import { classNames } from '../utils/classnames.js';
import { EditorPanel } from './EditorPanel.js';
import { PreviewPanel, type ImperativePreviewHandle } from './PreviewPanel.js';
import { TerminalPanel } from './TerminalPanel.js';
import { classNames } from '../utils/classnames.js';

const DEFAULT_TERMINAL_SIZE = 25;

Expand Down Expand Up @@ -154,6 +155,7 @@ export function WorkspacePanel({ tutorialStore, theme }: Props) {
showFileTree={fileTree}
editorDocument={currentDocument}
files={lesson.files[1]}
i18n={lesson.data.i18n as I18n}
hideRoot={lesson.data.hideRoot}
helpAction={helpAction}
onHelpClick={onHelpClick}
Expand Down Expand Up @@ -181,6 +183,7 @@ export function WorkspacePanel({ tutorialStore, theme }: Props) {
>
<PreviewPanel
tutorialStore={tutorialStore}
i18n={lesson.data.i18n as I18n}
ref={previewRef}
showToggleTerminal={!hideTerminalPanel}
toggleTerminal={toggleTerminal}
Expand Down
3 changes: 3 additions & 0 deletions packages/types/src/entities/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { I18nSchema } from '../schemas/i18n.js';
import type { ChapterSchema, LessonSchema, PartSchema } from '../schemas/index.js';

export type * from './nav.js';
Expand Down Expand Up @@ -51,6 +52,8 @@ export interface Lesson<T = unknown> {
Markdown: T;
}

export type I18n = Required<NonNullable<I18nSchema>>;

export interface Tutorial {
logoLink?: string;
firstPartId?: string;
Expand Down
35 changes: 35 additions & 0 deletions packages/types/src/schemas/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,41 @@ export const i18nSchema = z.object({
* @default 'No preview to run nor steps to show'
*/
noPreviewNorStepsText: z.string().optional(),

/**
* Text shown on top of the file tree.
*
* @default 'Files'
*/
filesTitleText: z.string().optional(),

/**
* Text shown on top of the steps section.
*
* @default 'Preparing Environment'
*/
prepareEnvironmentTitleText: z.string().optional(),

/**
* Text shown for the toggle terminal button.
*
* @default 'Toggle Terminal'
*/
toggleTerminalButtonText: z.string().optional(),

/**
* Text shown for the solve button.
*
* @default 'Solve'
*/
solveButtonText: z.string().optional(),

/**
* Text shown for the reset button.
*
* @default 'Reset'
*/
resetButtonText: z.string().optional(),
});

export type I18nSchema = z.infer<typeof i18nSchema>;