Labels and translation
Every word the library shows on its own, from Play to the scan's headlines, lives in one object: DEFAULT_LABELS. Wrap any part of your page in WrappedProvider and hand it the words you want instead. Use it to translate the interface, or just to make it sound like your product.
Twój rok ukrywa 4 sceny.
Twoje osiągnięcia i kilka niespodzianek. Każda trafia do filmu, gdy skan ją znajdzie.
- Wciąż ukryte
- Wciąż ukryte
- Wciąż ukryte
- Wciąż ukryte
The year scan in Polish. Run it: the headlines count in Polish too.
import {
type CalendarLevels,
resolvePalette,
type WrappedConfig,
type WrappedLabelOverrides,
WrappedProvider,
} from "@react-wrapped/core";
import { type HiddenDrop, useOpenedDrops, YearScan } from "@react-wrapped/scan";
/** Polish needs three forms of a counted noun: 1 scena, 2 sceny, 5 scen. A label is a function, so it can have them. */
const scenes = (count: number) => {
const few = count % 10 >= 2 && count % 10 <= 4 && (count % 100 < 12 || count % 100 > 14);
return `${count} ${count === 1 ? "scenę" : few ? "sceny" : "scen"}`;
};
// Only what this page shows is translated. Everything left out stays in English.
const POLISH: WrappedLabelOverrides = {
scan: {
hiding: (count) => `Twój rok ukrywa ${scenes(count)}.`,
about: "Twoje osiągnięcia i kilka niespodzianek. Każda trafia do filmu, gdy skan ją znajdzie.",
scanning: (left) => `Skanuję twój rok. Zostało jeszcze: ${left}.`,
scanningLast: "Szukam ostatniej.",
foundAll: (count) => `Wszystkie znalezione: ${count}.`,
moreHiding: (count) => `W twoim roku kryje się jeszcze: ${count}.`,
done: "Są już w twoim filmie. Uruchom skan ponownie, żeby zobaczyć je jeszcze raz.",
start: "Skanuj mój rok",
resume: "Skanuj dalej",
findAll: "Znajdź wszystkie",
again: "Skanuj ponownie",
finds: "Twoje znaleziska",
stillHidden: "Wciąż ukryte",
foundOn: (day) => `Znalezione: ${day}`,
},
rarity: { common: "Pospolite", rare: "Rzadkie", epic: "Epickie", legendary: "Legendarne" },
};
export function ScanInPolish({
calendar,
drops,
describeDay,
config,
}: {
calendar: CalendarLevels;
drops: readonly HiddenDrop[];
describeDay: (day: number) => string;
config: WrappedConfig;
}) {
const { opened, open } = useOpenedDrops(null);
return (
// Everything inside the provider reads its words from it. Numbers are written the way `locale` writes them.
<WrappedProvider labels={POLISH} locale="pl-PL">
<YearScan
calendar={calendar}
palette={resolvePalette(config)}
drops={drops}
found={opened}
onOpen={open}
describeDay={describeDay}
/>
</WrappedProvider>
);
}How it works
- Replace only what you need.
labelsis a partial ofDEFAULT_LABELS. Anything you leave out stays as it is. - A sentence with a number in it is a function.
scan.hidinggets the count and returns the sentence, so a language with three plural forms can have all three. - Providers nest. One around your app can set the language, and one around a single player can reword that player. The inner one is merged over the outer one.
- No provider is fine. Without one, every part reads the English defaults.
- It restyles too. The same provider takes
classNames, a class per part for everything under it. That is covered in styling. - Your scenes are yours. The text you pass to a scene is never touched. Labels cover only the words the library adds itself.
The groups
| Group | What it holds |
|---|---|
player | The transport under the video: play, pause, full screen, the clock. |
timeline | The row of segments and the preview that opens over one. |
editor | The scene editor: its title, its buttons, the transition picker. |
fields | A scene's editable fields, by their English name: { Headline: "Nagłówek" }. |
settings | The settings panel: colours, format, cells, speed, grain. |
scan | The year scan: its headline for every state, its buttons, the card it turns over. |
gallery | The graphics to keep: heading, locked tiles, download buttons. |
share | Copy link, Download, and the line shown while the video file is made. |
video | Why a video file could not be made. |
rarity | Common, Rare, Epic, Legendary. |
scenes, charts | The few words the ready-made scenes and charts print on their own. |
palettes, transitions, formats | Names by id. Empty by default: a missing id keeps its built-in name. |
The object is typed, so your editor lists every key and what each function is given. Read DEFAULT_LABELS in @react-wrapped/core for the full English text.
Props
| Prop | Type | What it does |
|---|---|---|
labels? | WrappedLabelOverrides | The words to replace, in the shape of DEFAULT_LABELS. Anything left out keeps its English. |
locale? | string | How the controls write numbers, such as "pl-PL". Left out, it is the provider's above, or "en-US". |
classNames? | SlotClassNames | A class per slot, such as "player-play", for every part under the provider. See styling. |
children? | ReactNode | Everything that should read its words from this provider. |
Outside React
Three functions draw without React and take their words as an argument: renderShareCard(spec, palette, { labels, locale }), renderInsightCard(spec, palette, { labels, locale }) and renderVideo(take, size, { labels }). Build the full table for them with mergeLabels(DEFAULT_LABELS, yours). Inside a component, useLabels() hands you the merged table of the nearest provider.
import { DEFAULT_LABELS, mergeLabels, resolvePalette } from "@react-wrapped/core";
import { renderShareCard } from "@react-wrapped/graphics";
const labels = mergeLabels(DEFAULT_LABELS, { rarity: { legendary: "Legendarne" } });
const png = await renderShareCard(card, resolvePalette(config), { labels, locale: "pl-PL" });What is not covered yet
- Numbers drawn inside the video itself (a counter, a chart's pill) are written the
en-USway: 1,687. Only the controls around the video followlocale. - Hour names in the charts (
hourName) are English. Pass your own labels in the chart's data where it takes them.
