Skip to content

Commit

Permalink
Internationalize more components (#49)
Browse files Browse the repository at this point in the history
  • Loading branch information
cdauth committed Jan 9, 2025
1 parent 9981511 commit 8c129dd
Show file tree
Hide file tree
Showing 12 changed files with 156 additions and 80 deletions.
File renamed without changes.
59 changes: 59 additions & 0 deletions assets/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,67 @@
"remove-tooltip": "Remove",
"new-song": "New song"
},
"song-player-toolbar": {
"clear-song-title": "Clear song",
"clear-song-message": "Do you really want to clear the current song?",
"clear-song-ok": "Clear",
"tools": "Tools",
"clear-song": "Clear song",
"export-mp3": "Export MP3",
"export-wav": "Export WAV",
"share": "Share",
"import": "Import"
},
"song-player": {
"all-instruments": "All",
"pick-intruments-tooltip": "Pick instruments",
"remove-tooltip": "Remove",
"all-instruments-drop": "(All)"
},
"help": {
"user-manual": "User manual",
"report-problem": "Report a problem",
"download": "Download {{appName}}",
"app": "{{appName}} app",
"source-code": "Source code on GitHub",
"language": "Language"
},
"overview": {
"listen": "Listen",
"compose": "Compose"
},
"config": {
"instruments-ls": "Low Surdo",
"instruments-ms": "Mid Surdo",
"instruments-hs": "High Surdo",
"instruments-re": "Repi",
"instruments-sn": "Snare",
"instruments-ta": "Tamborim",
"instruments-ag": "Agogô",
"instruments-sh": "Shaker",
"instruments-ot": "Shouting",
"stroke-description-hd": "Slap with hand",
"stroke-description-0": "Damp with hand",
"stroke-description-sil": "Silent stroke",
"stroke-description-fl": "Flare",
"stroke-description-w": "Whippy (tamborim) stick",
"stroke-description-.": "Silent stroke",
"stroke-description-wh": "Whistle",
"stroke-description-wh2": "Long whistle",
"stroke-description-s": "Soft flare",
"time-with-triplets": "{{time}} with triplets",
"time-with-quintuplets": "{{time}} with quintuplets",
"category-all": "All tunes",
"category-common": "Common tunes",
"category-uncommon": "Uncommon tunes",
"category-new": "New tunes",
"category-proposed": "Proposed tunes",
"category-custom": "Custom tunes",
"category-onesurdo": "One Surdo",
"category-easy": "Easy",
"category-medium": "Medium",
"category-tricky": "Tricky",
"category-wester": "Western music",
"category-cultural-appropriation": "Cultural appropriation"
}
}
86 changes: 43 additions & 43 deletions src/config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as z from "zod";
import { getI18n } from "./services/i18n";

const instrumentKeys = ["ls", "ms", "hs", "re", "sn", "ta", "ag", "sh", "ot"] as const;
export const instrumentValidator = z.enum(instrumentKeys);
Expand All @@ -21,7 +22,7 @@ export type Config = {
instrumentKeys: Instrument[];

instruments: Record<Instrument, {
name: string;
name: () => string;
/** The strokes that this instrument can play. Defines what options the stroke picker will display. */
strokes: Array<Stroke>;
}>;
Expand All @@ -30,7 +31,7 @@ export type Config = {
strokes: Record<Stroke, string>;

/** Optionally defining a tooltip that will describe a particular stroke further. */
strokesDescription: Partial<Record<Stroke, string>>;
strokesDescription: Partial<Record<Stroke, () => string>>;

/** Presets for the values of the instrument volume sliders, by preset name. */
volumePresets: Record<string, Record<Instrument, number>>;
Expand All @@ -39,7 +40,7 @@ export type Config = {
* The available time signatures. The key is the number of strokes per beat (the number of beats per bar is fixed to 4), the value is
* the name of the time measurement as it should be shown in the UI.
*/
times: Record<number, string>;
times: Record<number, () => string>;

/**
* The stroke resolution that will be used throughout the app, in number of strokes per beat (the number of beats per bar is fixed to 4).
Expand All @@ -49,7 +50,7 @@ export type Config = {
playTime: number;

/** The available tune filter categories mapped to their display name. */
filterCats: Record<Category, string>;
filterCats: Record<Category, () => string>;

/**
* The current tune of the year. It will be opened by default when the app is opened. If multiple tunes are specified, one of them will be
Expand All @@ -70,39 +71,39 @@ const config: Config = {

instruments: {
ls: {
name: "Low Surdo",
name: () => getI18n().t("config.instruments-ls"),
strokes: [ "X", "0", "s", "t", "r" ]
},
ms: {
name: "Mid Surdo",
name: () => getI18n().t("config.instruments-ms"),
strokes: [ "X", "0", "s", "t", "r" ]
},
hs: {
name: "High Surdo",
name: () => getI18n().t("config.instruments-hs"),
strokes: [ "X", "0", "s", "t", "r" ]
},
re: {
name: "Repi",
name: () => getI18n().t("config.instruments-re"),
strokes: [ "X", "f", "r", "h", ".", "z", "s" ]
},
sn: {
name: "Snare",
name: () => getI18n().t("config.instruments-sn"),
strokes: [ ".", "X", "r", "f" ]
},
ta: {
name: "Tamborim",
name: () => getI18n().t("config.instruments-ta"),
strokes: [ "X", "r", "f" ]
},
ag: {
name: "Agogô",
name: () => getI18n().t("config.instruments-ag"),
strokes: [ "o", "a", "r", "." ]
},
sh: {
name: "Shaker",
name: () => getI18n().t("config.instruments-sh"),
strokes: [ "X", "." ]
},
ot: {
name: "Shouting",
name: () => getI18n().t("config.instruments-ot"),
strokes: [ "w", "y", "A", "B", "D", "E", "F", "G", "J", "K", "L", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "Y", "Z", "9", "8", "7", "6", "5", "b", "c", "d", "e", "g", "q", "j", "k", "m", "n", "u", "v", "x", "i", "l", "p", "$", "%", "&", "'", "(", ")", "*", ",", "-", "?", ":", ";", "<", "=", ">", "K", "[", "\\", "^", "_", "`", "{", "|", "}", "~", "À", "Á", "Â", "Ã", "Ä", "Å", "Æ", "Ç", "È", "É", "Ê", "Ë", "Ì", "Í", "Î", "Ï", "İ", "Ǐ", "Ī", "Ĩ", "Į", "IJ", "Ð", "Ñ", "Ò", "Ó", "Ô" ]
}
},
Expand Down Expand Up @@ -227,16 +228,15 @@ const config: Config = {
},

strokesDescription: {
"h": "Hand",
"i": "Slap with hand",
"0": "Damp with hand",
"s": "Silent stroke",
"f": "Flare",
"t": "Whippy (tamborim) stick",
".": "Silent stroke",
"w" : "Whistle",
"y" : "Long whistle",
"z": "Soft flare"
"h": () => getI18n().t("config.stroke-description-hd"),
"0": () => getI18n().t("config.stroke-description-0"),
"s": () => getI18n().t("config.stroke-description-sil"),
"f": () => getI18n().t("config.stroke-description-fl"),
"t": () => getI18n().t("config.stroke-description-w"),
".": () => getI18n().t("config.stroke-description-."),
"w" :() => getI18n().t("config.stroke-description-wh"),
"y" :() => getI18n().t("config.stroke-description-wh2"),
"z": () => getI18n().t("config.stroke-description-s")
},

volumePresets: {
Expand Down Expand Up @@ -265,32 +265,32 @@ const config: Config = {
},

times: {
2: "2⁄4",
3: "6⁄8",
4: "4⁄4",
5: "5⁄8",
6: "3⁄4",
8: "8⁄8",
12: "4⁄4 with triplets",
20: "4⁄4 with quintuplets"
2: () => "2⁄4",
3: () => "6⁄8",
4: () => "4⁄4",
5: () => "5⁄8",
6: () => "3⁄4",
8: () => "8⁄8",
12: () => getI18n().t("config.time-with-triplets", { time: "4⁄4" }),
20: () => getI18n().t("config.time-with-quintuplets", { time: "4⁄4" })
},

// Time measurement that is used for beatbox.js. Should be able to represent all the time measurements above
playTime: 120,

filterCats: {
all: "All tunes",
common: "Common tunes",
uncommon: "Uncommon tunes",
new: "New tunes",
proposed: "Proposed tunes",
custom: "Custom tunes",
onesurdo: "One Surdo",
easy: "Easy",
medium: "Medium",
tricky: "Tricky",
western: "Western music",
"cultural-appropriation": "Cultural appropriation"
all: () => getI18n().t("config.category-all"),
common: () => getI18n().t("config.category-common"),
uncommon: () => getI18n().t("config.category-uncommon"),
new: () => getI18n().t("config.category-new"),
proposed: () => getI18n().t("config.category-proposed"),
custom: () => getI18n().t("config.category-custom"),
onesurdo: () => getI18n().t("config.category-onesurdo"),
easy: () => getI18n().t("config.category-easy"),
medium: () => getI18n().t("config.category-medium"),
tricky: () => getI18n().t("config.category-tricky"),
western: () => getI18n().t("config.category-western"),
"cultural-appropriation": () => getI18n().t("config.category-cultural-appropriation")
},

tuneOfTheYear: "The Roof Is on Fire",
Expand Down
12 changes: 11 additions & 1 deletion src/services/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,18 @@ i18n.init({
});

const TUNE_DESCRIPTIONS_NS = "tune-descriptions";

for (const [filename, module] of Object.entries(import.meta.glob('../../assets/tuneDescriptions/*/*.md', { eager: true }))) {
const m = filename.match(/([^/\\]+)[/\\]([^/\\]+)\.md/)!;
i18n.addResource(m[2], TUNE_DESCRIPTIONS_NS, m[1], (module as any).html);
}

const APP_INSTRUCTIONS_NS = "app-instructions";
const APP_INSTRUCTIONS_KEY = "app-instructions";
for (const [filename, module] of Object.entries(import.meta.glob('../../assets/appInstructions/*.md', { eager: true }))) {
const m = filename.match(/([^/\\]+)\.md/)!;
i18n.addResource(m[1], APP_INSTRUCTIONS_NS, APP_INSTRUCTIONS_KEY, (module as any).html);
}

const i18nResourceChangeCounter = ref(0);
const onI18nResourceChange = () => {
i18nResourceChangeCounter.value++;
Expand Down Expand Up @@ -92,4 +98,8 @@ export function useI18n(): ReturnType<typeof getI18n> {

export function getTuneDescriptionHtml(tuneName: string): string {
return i18n.t(tuneName, { ns: TUNE_DESCRIPTIONS_NS, defaultValue: "" });
}

export function getAppInstructionsHtml(): string {
return i18n.t(APP_INSTRUCTIONS_KEY, { ns: APP_INSTRUCTIONS_NS });
}
21 changes: 12 additions & 9 deletions src/ui/compose/song-player-toolbar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import SongPicker from "./song-picker.vue";
import PlayPauseStopButton from "../play-pause-stop-button.vue";
import { download, ExportType } from "../utils/export";
import { useI18n } from "../../services/i18n";
const props = defineProps<{
player: BeatboxReference;
Expand All @@ -21,6 +22,8 @@
"update:songIdx": [songIdx: number];
}>();
const i18n = useI18n();
const state = injectStateRequired();
const songIdx = computed({
Expand All @@ -37,10 +40,10 @@
const handleClearSong = async () => {
if(await showConfirm({
title: "Clear song",
message: "Do you really want to clear the current song?",
title: i18n.t("song-player-toolbar.clear-song-title"),
message: i18n.t("song-player-toolbar.clear-song-message"),
variant: "danger",
okLabel: "Clear"
okLabel: i18n.t("song-player-toolbar.clear-song-ok")
})) {
clearSong(song.value);
}
Expand All @@ -66,14 +69,14 @@

<div class="dropdown">
<button class="btn btn-secondary dropdown-toggle" data-bs-toggle="dropdown">
<fa icon="cog"/><span class="d-none d-sm-inline"> Tools</span>
<fa icon="cog"/><span class="d-none d-sm-inline">{{" "}}{{i18n.t("song-player-toolbar.tools")}}</span>
</button>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="javascript:" @click="handleClearSong()" draggable="false"><fa icon="trash" fixed-width/> Clear song</a></li>
<li><a class="dropdown-item" href="javascript:" @click="handleDownload(ExportType.MP3)" draggable="false"><fa icon="file-export" fixed-width/> Export MP3</a></li>
<li><a class="dropdown-item" href="javascript:" @click="handleDownload(ExportType.WAV)" draggable="false"><fa icon="file-export" fixed-width/> Export WAV</a></li>
<li><a class="dropdown-item" href="javascript:" @click="showShareDialog = true" draggable="false"><fa icon="share" fixed-width/> Share</a></li>
<li><a class="dropdown-item" href="javascript:" @click="showImportDialog = true" draggable="false"><fa icon="file-import" fixed-width/> Import</a></li>
<li><a class="dropdown-item" href="javascript:" @click="handleClearSong()" draggable="false"><fa icon="trash" fixed-width/>{{" "}}{{i18n.t("song-player-toolbar.clear-song")}}</a></li>
<li><a class="dropdown-item" href="javascript:" @click="handleDownload(ExportType.MP3)" draggable="false"><fa icon="file-export" fixed-width/>{{" "}}{{i18n.t("song-player-toolbar.export-mp3")}}</a></li>
<li><a class="dropdown-item" href="javascript:" @click="handleDownload(ExportType.WAV)" draggable="false"><fa icon="file-export" fixed-width/>{{" "}}{{i18n.t("song-player-toolbar.export-wav")}}</a></li>
<li><a class="dropdown-item" href="javascript:" @click="showShareDialog = true" draggable="false"><fa icon="share" fixed-width/>{{" "}}{{i18n.t("song-player-toolbar.share")}}</a></li>
<li><a class="dropdown-item" href="javascript:" @click="showImportDialog = true" draggable="false"><fa icon="file-import" fixed-width/>{{" "}}{{i18n.t("song-player-toolbar.import")}}</a></li>
</ul>
</div>

Expand Down
15 changes: 9 additions & 6 deletions src/ui/compose/song-player.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import vTooltip from "../utils/tooltip";
import { useRefWithOverride } from "../../utils";
import AbstractPlayer, { PositionData } from "../utils/abstract-player.vue";
import { useI18n } from "../../services/i18n";
type DragOver = "trash" | { instr?: Instrument; idx: number };
</script>
Expand All @@ -31,6 +32,8 @@
"update:isDraggingPattern": [isDraggingPattern: boolean];
}>();
const i18n = useI18n();
const state = injectStateRequired();
const songIdx = computed({
Expand Down Expand Up @@ -325,9 +328,9 @@
<div class="bb-col instruments">
<div class="timeline"></div>
<div class="field" v-for="instrumentKey in config.instrumentKeys" :key="instrumentKey">
{{config.instruments[instrumentKey].name}}
{{config.instruments[instrumentKey].name()}}
</div>
<div class="field all-drop">All</div>
<div class="field all-drop">{{i18n.t("song-player.all-instruments")}}</div>
</div><div class="bb-col instrument-actions">
<div class="timeline">
<MuteButton instrument="all" v-model:playbackSettings="state.playbackSettings"/>
Expand Down Expand Up @@ -366,7 +369,7 @@
<PatternPlaceholderItem>
<div class="dropdown">
<a href="javascript" data-bs-toggle="dropdown">
<fa icon="hand-point-right" v-tooltip="'Pick instruments'"/>
<fa icon="hand-point-right" v-tooltip="i18n.t('song-player.pick-intruments-tooltip')"/>
</a>
<ul class="dropdown-menu">
<li v-for="instrumentKey2 in config.instrumentKeys" :key="instrumentKey2">
Expand All @@ -375,13 +378,13 @@
href="javascript:"
@click="toggleInstrument(instrumentKey2, i-1, song[i-1][instrumentKey]!)"
draggable="false"
><fa icon="check" :style="{visibility: isEqual(song[i-1][instrumentKey2], song[i-1][instrumentKey]) ? 'visible' : 'hidden'}"></fa> {{config.instruments[instrumentKey2].name}}</a>
><fa icon="check" :style="{visibility: isEqual(song[i-1][instrumentKey2], song[i-1][instrumentKey]) ? 'visible' : 'hidden'}"></fa> {{config.instruments[instrumentKey2].name()}}</a>
</li>
</ul>
</div>
</PatternPlaceholderItem>
<PatternPlaceholderItem>
<a href="javascript:" @click="removePatternFromSong(instrumentKey, i-1)" v-tooltip="'Remove'" draggable="false"><fa icon="trash" /></a>
<a href="javascript:" @click="removePatternFromSong(instrumentKey, i-1)" v-tooltip="i18n.t('song-player.remove-tooltip')" draggable="false"><fa icon="trash" /></a>
</PatternPlaceholderItem>
</PatternPlaceholder>
<span class="placeholder-drag-handle" draggable="true" @dragstart="handleResizeDragStart($event, instrumentKey, i-1)" @dragend="handleResizeDragEnd($event)"><span class="caret-se"></span></span>
Expand All @@ -395,7 +398,7 @@
@dragleave="handleDragLeave($event, { idx: i-1 })"
@drop="handleDrop($event)"
>
(All)
{{i18n.t("song-player.all-instruments-drop")}}
</div>
</div></div>

Expand Down
Loading

0 comments on commit 8c129dd

Please sign in to comment.