mirror of
https://github.com/zoriya/v10.git
synced 2026-08-16 02:45:09 +00:00
fix(i18n): align stack after phrase key rollout
This commit is contained in:
@@ -1,13 +1,13 @@
|
||||
/**
|
||||
* Loads overlay layers for each tag in {@link localeLookupChain}, least-specific first, then merges
|
||||
* Loads overlay layers for each resolved locale key, least-specific first, then merges
|
||||
* most-specific-last (same semantics as the core i18n registry).
|
||||
*/
|
||||
export async function mergeLocaleOverlays<Overlay extends object>(
|
||||
locale: string,
|
||||
load: (tag: string) => Promise<Partial<Overlay> | undefined>,
|
||||
localeLookupChain: (locale: string) => string[]
|
||||
findKeys: (locale: string) => string[]
|
||||
): Promise<{ merged: Partial<Overlay>; loadedTags: string[] }> {
|
||||
const chain = localeLookupChain(locale);
|
||||
const chain = findKeys(locale);
|
||||
const layers = await Promise.all(chain.map((tag) => load(tag)));
|
||||
const loadedTags: string[] = [];
|
||||
const merged: Partial<Overlay> = {};
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
---
|
||||
title: Internationalization
|
||||
description: How Video.js translates player UI copy with opaque keys, a global registry, and locale providers
|
||||
description: How Video.js translates player UI copy with English phrase keys, a global registry, and locale providers
|
||||
---
|
||||
|
||||
import FrameworkCase from '@/components/docs/FrameworkCase.astro';
|
||||
import Aside from '@/components/Aside.astro';
|
||||
import DocsLink from '@/components/docs/DocsLink.astro';
|
||||
|
||||
Video.js translates control labels, ARIA text, tooltips, and error copy through a single **global registry**. Components ask for strings by **opaque key** (`play`, `pause`, `seekForward`), not by English text, so locale files stay stable when copy changes.
|
||||
Video.js translates control labels, ARIA text, tooltips, and error copy through a single **global registry**. Components ask for strings by current English phrase (`Play`, `Pause`, `Seek forward {seconds} seconds`), so missing translations stay readable.
|
||||
|
||||
<FrameworkCase frameworks={["html"]}>
|
||||
|
||||
@@ -44,13 +44,13 @@ export function App() {
|
||||
|
||||
Register a locale once (or rely on lazy-loaded built-in packs), set `lang`, and skins pick up translated strings automatically.
|
||||
|
||||
## Opaque keys
|
||||
## Phrase keys
|
||||
|
||||
Core controls expose keys, not visible labels. `PlayButtonCore.getLabel()` returns `'play'`; the translator turns that into `'Play'`, `'Reproducir'`, or your override.
|
||||
Core controls expose current English phrases. `PlayButtonCore.getLabel()` returns `'Play'`; the translator turns that into `'Play'`, `'Reproducir'`, or your override.
|
||||
|
||||
Keys are typed in <DocsLink slug="reference/translation-params">`TranslationParams`</DocsLink>. TypeScript catches missing `{param}` placeholders and wrong argument names at compile time.
|
||||
Phrase params are typed in <DocsLink slug="reference/translation-params">`TranslationParams`</DocsLink>. TypeScript catches missing `{param}` placeholders and wrong argument names at compile time.
|
||||
|
||||
Parametric strings use `{placeholder}` tokens, for example `seekForward: 'Seek forward {seconds} seconds'` and `timeRemainingPhrase: '{duration} remaining'`.
|
||||
Parametric strings use `{placeholder}` tokens, for example `'Seek forward {seconds} seconds'` and `'{duration} remaining'`.
|
||||
|
||||
## Global registry
|
||||
|
||||
@@ -60,7 +60,7 @@ Parametric strings use `{placeholder}` tokens, for example `seekForward: 'Seek f
|
||||
| --- | --- |
|
||||
| <DocsLink slug="reference/register-i18n">`registerI18n`</DocsLink> | Add or merge a locale layer |
|
||||
| <DocsLink slug="reference/get-i18n-translations">`getI18nTranslations`</DocsLink> | Read the merged map for a locale |
|
||||
| <DocsLink slug="reference/has-registered-i18n">`hasRegisteredI18n`</DocsLink> | Check whether a tag is in the registry |
|
||||
| <DocsLink slug="reference/has-registered-locale">`hasRegisteredLocale`</DocsLink> | Check whether a tag is in the registry |
|
||||
| <DocsLink slug="reference/on-i18n-registry-change">`onI18nRegistryChange`</DocsLink> | Subscribe to registry updates |
|
||||
|
||||
Import from `@videojs/html/i18n` or `@videojs/react/i18n` depending on your framework.
|
||||
@@ -108,7 +108,7 @@ es-MX → es → en
|
||||
zh-Hant-HK → zh-hant → zh → en
|
||||
```
|
||||
|
||||
`getI18nTranslations`, lazy `loadLocale`, and providers all use the same chain via `localeLookupChain`.
|
||||
`getI18nTranslations`, lazy `loadLocale`, and providers all use the same chain via `findLocaleKeys`.
|
||||
|
||||
## Merge priority
|
||||
|
||||
@@ -136,19 +136,19 @@ CDN consumers load self-registering modules:
|
||||
## Common pitfalls
|
||||
|
||||
```tsx
|
||||
// ❌ Don't: key is the English word; keys are opaque tokens
|
||||
registerI18n('es', { Play: 'Reproducir' });
|
||||
// ❌ Don't: old camelCase keys are ignored
|
||||
registerI18n('es', { play: 'Reproducir' });
|
||||
|
||||
// ✅ Do
|
||||
registerI18n('es', { play: 'Reproducir' });
|
||||
registerI18n('es', { Play: 'Reproducir' });
|
||||
```
|
||||
|
||||
```tsx
|
||||
// ❌ Don't: parametric key without the placeholder
|
||||
registerI18n('es', { seekForward: 'Adelante 10 segundos' }); // TS error: missing {seconds}
|
||||
registerI18n('es', { 'Seek forward {seconds} seconds': 'Adelante 10 segundos' }); // TS error: missing {seconds}
|
||||
|
||||
// ✅ Do
|
||||
registerI18n('es', { seekForward: 'Adelantar {seconds} segundos' });
|
||||
registerI18n('es', { 'Seek forward {seconds} seconds': 'Adelantar {seconds} segundos' });
|
||||
```
|
||||
|
||||
<Aside type="tip">
|
||||
|
||||
@@ -13,7 +13,7 @@ This guide is for **contributors** adding or updating shipped packs. App authors
|
||||
### Prerequisites
|
||||
|
||||
- Familiarity with <DocsLink slug="concepts/i18n">Internationalization</DocsLink> and <DocsLink slug="reference/translation-params">`TranslationParams`</DocsLink>
|
||||
- English defaults in `packages/core/src/core/i18n/locales/en.ts` as the source of keys
|
||||
- English defaults in `packages/core/src/core/i18n/locales/en.ts` as the source of phrases
|
||||
|
||||
## 1. Add the locale file
|
||||
|
||||
@@ -23,24 +23,24 @@ Create `packages/core/src/core/i18n/locales/{tag}.ts` using the BCP 47 tag as th
|
||||
import type { Translations } from '../types';
|
||||
|
||||
export default {
|
||||
play: '…',
|
||||
pause: '…',
|
||||
// all keys from en.ts; completeness is preferred
|
||||
Play: '…',
|
||||
Pause: '…',
|
||||
// all phrases from en.ts; completeness is preferred
|
||||
} satisfies Partial<Translations>;
|
||||
```
|
||||
|
||||
Use **opaque keys** from `en.ts`, not English sentences as keys. Parametric strings must include the same `{placeholder}` tokens (TypeScript enforces this via `satisfies Partial<Translations>`).
|
||||
Use the current English phrases from `en.ts`. Parametric strings must include the same `{placeholder}` tokens (TypeScript enforces this via `satisfies Partial<Translations>`).
|
||||
|
||||
Copy guidelines:
|
||||
|
||||
- `liveBadge`: sentence case (`Live`); skins uppercase via CSS where needed
|
||||
- `seek`: slider aria label (`Seek`), not legacy "Progress" wording
|
||||
- `timeRemainingPhrase`: `'{duration} remaining'` pattern with `{duration}` placeholder
|
||||
- `Live`: sentence case; skins uppercase via CSS where needed
|
||||
- `Seek`: slider aria label, not legacy "Progress" wording
|
||||
- `'{duration} remaining'`: pattern with `{duration}` placeholder
|
||||
- Button and error strings: short aria-label style, aligned with V10 core label usage
|
||||
|
||||
## 2. Register the tag in built-in metadata
|
||||
|
||||
Add the tag to `BUILT_IN_LOCALES` in `packages/core/src/core/i18n/built-in-locales.ts`. Add alias tags (`pt`, `zh`) to `LOCALE_ALIAS_TAGS` only when intentional.
|
||||
Add the tag to `LOCALES` in `packages/core/src/core/i18n/locales.ts`.
|
||||
|
||||
## 3. Regenerate loaders
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
---
|
||||
title: Override translation keys
|
||||
title: Override translations
|
||||
description: Patch individual i18n strings without replacing an entire locale pack
|
||||
---
|
||||
|
||||
import FrameworkCase from '@/components/docs/FrameworkCase.astro';
|
||||
import DocsLink from '@/components/docs/DocsLink.astro';
|
||||
|
||||
`registerI18n` **merges**. Each call adds or replaces keys for that locale tag without wiping prior registrations. Use this to tweak shipped packs or A/B test copy.
|
||||
`registerI18n` **merges**. Each call adds or replaces phrases for that locale tag without wiping prior registrations. Use this to tweak shipped packs or A/B test copy.
|
||||
|
||||
Read <DocsLink slug="concepts/i18n">Internationalization</DocsLink> for merge order and key naming.
|
||||
Read <DocsLink slug="concepts/i18n">Internationalization</DocsLink> for merge order and phrase naming.
|
||||
|
||||
## Override after a built-in pack
|
||||
|
||||
@@ -17,10 +17,10 @@ import { registerI18n } from '@videojs/html/i18n';
|
||||
import es from '@videojs/html/i18n/locales/es';
|
||||
|
||||
registerI18n('es', es);
|
||||
registerI18n('es', { play: 'Comenzar' }); // only `play` changes
|
||||
registerI18n('es', { Play: 'Comenzar' }); // only `Play` changes
|
||||
```
|
||||
|
||||
Later registrations win for the same key. The rest of the `es` pack stays intact.
|
||||
Later registrations win for the same phrase. The rest of the `es` pack stays intact.
|
||||
|
||||
## React provider overrides
|
||||
|
||||
@@ -33,7 +33,7 @@ import { I18nProvider } from '@videojs/react/i18n';
|
||||
import { Provider, VideoSkin, Video } from '@videojs/react/video';
|
||||
|
||||
<Provider>
|
||||
<I18nProvider locale="es" translations={{ play: 'Comenzar' }}>
|
||||
<I18nProvider locale="es" translations={{ Play: 'Comenzar' }}>
|
||||
<VideoSkin>
|
||||
<Video src="..." playsInline />
|
||||
</VideoSkin>
|
||||
@@ -45,8 +45,8 @@ Nested providers inherit the parent locale when you only pass `translations`:
|
||||
|
||||
```tsx
|
||||
<I18nProvider locale="de">
|
||||
<I18nProvider translations={{ play: 'Override' }}>
|
||||
{/* locale stays `de`; only `play` differs */}
|
||||
<I18nProvider translations={{ Play: 'Override' }}>
|
||||
{/* locale stays `de`; only `Play` differs */}
|
||||
</I18nProvider>
|
||||
</I18nProvider>
|
||||
```
|
||||
@@ -59,22 +59,22 @@ Use <DocsLink slug="reference/media-text">`<media-text>`</DocsLink> for static c
|
||||
|
||||
```html
|
||||
<media-i18n-provider lang="es">
|
||||
<media-text key="play"></media-text>
|
||||
<media-text key="Play"></media-text>
|
||||
</media-i18n-provider>
|
||||
```
|
||||
|
||||
Override the key in the registry or set `lang` on the provider to a locale where you patched `play`.
|
||||
Override the phrase in the registry or set `lang` on the provider to a locale where you patched `Play`.
|
||||
|
||||
## Parametric keys
|
||||
## Parametric phrases
|
||||
|
||||
Keep required placeholders when overriding:
|
||||
|
||||
```ts
|
||||
// ✅
|
||||
registerI18n('es', { seekForward: 'Adelantar {seconds} segundos' });
|
||||
registerI18n('es', { 'Seek forward {seconds} seconds': 'Adelantar {seconds} segundos' });
|
||||
|
||||
// ❌ TypeScript error: missing {seconds}
|
||||
registerI18n('es', { seekForward: 'Adelantar' });
|
||||
registerI18n('es', { 'Seek forward {seconds} seconds': 'Adelantar' });
|
||||
```
|
||||
|
||||
## What's next?
|
||||
|
||||
@@ -7,12 +7,12 @@ import FrameworkCase from '@/components/docs/FrameworkCase.astro';
|
||||
import Aside from '@/components/Aside.astro';
|
||||
import DocsLink from '@/components/docs/DocsLink.astro';
|
||||
|
||||
Register strings once with <DocsLink slug="reference/register-i18n">`registerI18n`</DocsLink>, then set `lang` on the page or pass `locale` to a provider. Read <DocsLink slug="concepts/i18n">Internationalization</DocsLink> first if you are new to opaque keys and the registry.
|
||||
Register strings once with <DocsLink slug="reference/register-i18n">`registerI18n`</DocsLink>, then set `lang` on the page or pass `locale` to a provider. Read <DocsLink slug="concepts/i18n">Internationalization</DocsLink> first if you are new to phrase keys and the registry.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- A locale tag ([BCP 47](https://www.rfc-editor.org/rfc/rfc5646), e.g. `es`, `pt-BR`)
|
||||
- A partial translation map keyed by camelCase tokens (`play`, `pause`, …)
|
||||
- A partial translation map keyed by current English phrases (`Play`, `Pause`, …)
|
||||
|
||||
## Use a shipped pack
|
||||
|
||||
@@ -74,10 +74,10 @@ Preset skins use `Container`, which includes <DocsLink slug="reference/i18n-prov
|
||||
import type { Translations } from '@videojs/html/i18n';
|
||||
|
||||
const es = {
|
||||
play: 'Reproducir',
|
||||
pause: 'Pausa',
|
||||
mute: 'Silenciar',
|
||||
unmute: 'Activar sonido',
|
||||
Play: 'Reproducir',
|
||||
Pause: 'Pausa',
|
||||
Mute: 'Silenciar',
|
||||
Unmute: 'Activar sonido',
|
||||
} satisfies Partial<Translations>;
|
||||
|
||||
export default es;
|
||||
@@ -91,10 +91,10 @@ export default es;
|
||||
import type { Translations } from '@videojs/react/i18n';
|
||||
|
||||
const es = {
|
||||
play: 'Reproducir',
|
||||
pause: 'Pausa',
|
||||
mute: 'Silenciar',
|
||||
unmute: 'Activar sonido',
|
||||
Play: 'Reproducir',
|
||||
Pause: 'Pausa',
|
||||
Mute: 'Silenciar',
|
||||
Unmute: 'Activar sonido',
|
||||
} satisfies Partial<Translations>;
|
||||
|
||||
export default es;
|
||||
@@ -138,8 +138,8 @@ CDN locale files import `registerI18n` from the shared `cdn/i18n.js` bundle so e
|
||||
import { registerI18n } from 'https://cdn.jsdelivr.net/npm/@videojs/html/cdn/i18n.js';
|
||||
|
||||
registerI18n('es', {
|
||||
play: 'Reproducir',
|
||||
pause: 'Pausa',
|
||||
Play: 'Reproducir',
|
||||
Pause: 'Pausa',
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
@@ -17,16 +17,14 @@ import es from '@videojs/html/i18n/locales/es';
|
||||
## Definition
|
||||
|
||||
```ts
|
||||
type BuiltInLocale =
|
||||
| (typeof BUILT_IN_LOCALES)[number]
|
||||
| (typeof LOCALE_ALIAS_TAGS)[number];
|
||||
type BuiltInLocale = (typeof LOCALES)[number];
|
||||
```
|
||||
|
||||
`BUILT_IN_LOCALES` lists regional packs (`es`, `pt-BR`, `zh-CN`, …). `LOCALE_ALIAS_TAGS` adds shorthand tags (`pt`, `zh`) that resolve to regional packs through the lookup chain.
|
||||
`LOCALES` lists shipped packs (`es`, `pt-BR`, `zh-CN`, …). Bare language tags such as `pt` and `zh` are handled by the normal locale lookup chain when there is a matching registered or loaded layer.
|
||||
|
||||
## Lazy loading
|
||||
|
||||
Providers call `loadLocale(tag)` for tags in `SHIPPED_LOCALE_TAGS` when a pack is not already registered. Explicit `registerI18n` or CDN locale modules skip the async gap on first paint.
|
||||
Providers call `loadLocale(tag)` for tags in the resolved locale chain when a pack is not already registered. Explicit `registerI18n` or CDN locale modules skip the async gap on first paint.
|
||||
|
||||
## Examples
|
||||
|
||||
|
||||
@@ -13,8 +13,8 @@ import { createTranslator, getI18nTranslations } from '@videojs/html/i18n';
|
||||
// or @videojs/react/i18n
|
||||
|
||||
const t = createTranslator(getI18nTranslations('fr'), 'fr');
|
||||
t('play');
|
||||
t('seekForward', { seconds: 5 });
|
||||
t('Play');
|
||||
t('Seek forward {seconds} seconds', { seconds: 5 });
|
||||
```
|
||||
|
||||
<UtilReference util="createTranslator" />
|
||||
|
||||
@@ -15,7 +15,7 @@ import { createTranslator, getI18nTranslations } from '@videojs/html/i18n';
|
||||
// or @videojs/react/i18n
|
||||
|
||||
const t = createTranslator(getI18nTranslations('pt-BR'), 'pt-BR');
|
||||
t('play'); // merged Portuguese string
|
||||
t('Play'); // merged Portuguese string
|
||||
```
|
||||
|
||||
<UtilReference util="getI18nTranslations" />
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
---
|
||||
title: hasRegisteredI18n
|
||||
description: Check whether an exact locale tag exists in the global i18n registry
|
||||
---
|
||||
|
||||
import UtilReference from "@/components/docs/api-reference/UtilReference.astro";
|
||||
import DocsLink from "@/components/docs/DocsLink.astro";
|
||||
|
||||
`hasRegisteredI18n` returns whether a normalized locale tag has an explicit registry layer from `registerI18n`. It does **not** indicate whether a lazy built-in pack exists. Only registry entries count.
|
||||
|
||||
```ts
|
||||
import { hasRegisteredI18n, registerI18n } from '@videojs/html/i18n';
|
||||
|
||||
hasRegisteredI18n('fr'); // false until registered
|
||||
registerI18n('fr', { play: 'Lecture' });
|
||||
hasRegisteredI18n('fr'); // true
|
||||
```
|
||||
|
||||
<UtilReference util="hasRegisteredI18n" />
|
||||
@@ -0,0 +1,19 @@
|
||||
---
|
||||
title: hasRegisteredLocale
|
||||
description: Check whether an exact locale tag exists in the global i18n registry
|
||||
---
|
||||
|
||||
import UtilReference from "@/components/docs/api-reference/UtilReference.astro";
|
||||
import DocsLink from "@/components/docs/DocsLink.astro";
|
||||
|
||||
`hasRegisteredLocale` returns whether a normalized locale tag has an explicit registry layer from `registerI18n`. It does **not** indicate whether a lazy built-in pack exists. Only registry entries count.
|
||||
|
||||
```ts
|
||||
import { hasRegisteredLocale, registerI18n } from '@videojs/html/i18n';
|
||||
|
||||
hasRegisteredLocale('fr'); // false until registered
|
||||
registerI18n('fr', { Play: 'Lecture' });
|
||||
hasRegisteredLocale('fr'); // true
|
||||
```
|
||||
|
||||
<UtilReference util="hasRegisteredLocale" />
|
||||
@@ -16,7 +16,7 @@ Wrap custom controls or force a locale explicitly:
|
||||
```tsx
|
||||
import { I18nProvider } from '@videojs/react/i18n';
|
||||
|
||||
<I18nProvider locale="de" translations={{ play: 'Abspielen' }}>
|
||||
<I18nProvider locale="de" translations={{ Play: 'Abspielen' }}>
|
||||
<MyControls />
|
||||
</I18nProvider>
|
||||
```
|
||||
|
||||
@@ -24,7 +24,7 @@ The `(string & {})` pattern keeps custom tags (`'xx'`, `'en-US'`) type-safe with
|
||||
|
||||
## Resolution
|
||||
|
||||
Providers and `getI18nTranslations` normalize tags and walk the parent chain (`es-MX` → `es` → `en`) via `localeLookupChain`. See <DocsLink slug="concepts/i18n">Internationalization</DocsLink> for explicit vs ambient resolution.
|
||||
Providers and `getI18nTranslations` normalize tags and walk the parent chain (`es-MX` → `es` → `en`) via `findLocaleKeys`. See <DocsLink slug="concepts/i18n">Internationalization</DocsLink> for explicit vs ambient resolution.
|
||||
|
||||
## Examples
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import FrameworkCase from "@/components/docs/FrameworkCase.astro";
|
||||
|
||||
`<media-i18n-provider>` applies the i18n provider mixin to a standalone subtree. Built-in `<video-player>` and skins already include this mixin — use the element when rendering **controls outside a player** or when sibling players need different locales.
|
||||
|
||||
Register locale strings with <DocsLink slug="reference/register-i18n">`registerI18n`</DocsLink>, then set `lang` on the provider or an ancestor. See <DocsLink slug="concepts/i18n">Internationalization</DocsLink> for opaque keys and fallback behavior.
|
||||
Register locale strings with <DocsLink slug="reference/register-i18n">`registerI18n`</DocsLink>, then set `lang` on the provider or an ancestor. See <DocsLink slug="concepts/i18n">Internationalization</DocsLink> for phrase keys and fallback behavior.
|
||||
|
||||
```html
|
||||
<script type="module">
|
||||
@@ -22,7 +22,7 @@ Register locale strings with <DocsLink slug="reference/register-i18n">`registerI
|
||||
</script>
|
||||
|
||||
<media-i18n-provider lang="es">
|
||||
<media-text key="play"></media-text>
|
||||
<media-text key="Play"></media-text>
|
||||
</media-i18n-provider>
|
||||
```
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: media-text
|
||||
description: HTML custom element that renders a translated string by opaque key
|
||||
description: HTML custom element that renders a translated string by phrase
|
||||
---
|
||||
|
||||
import DocsLink from "@/components/docs/DocsLink.astro";
|
||||
@@ -8,11 +8,11 @@ import FrameworkCase from "@/components/docs/FrameworkCase.astro";
|
||||
|
||||
<FrameworkCase frameworks={["html"]}>
|
||||
|
||||
`<media-text>` renders the translated value for a registry key inside a <DocsLink slug="reference/media-i18n-provider">`<media-i18n-provider>`</DocsLink> (or any ancestor with the i18n provider mixin). Use it for standalone labels, tooltips, or demos — skin controls resolve keys internally.
|
||||
`<media-text>` renders the translated value for a registry phrase inside a <DocsLink slug="reference/media-i18n-provider">`<media-i18n-provider>`</DocsLink> (or any ancestor with the i18n provider mixin). Use it for standalone labels, tooltips, or demos — skin controls resolve phrases internally.
|
||||
|
||||
```html
|
||||
<media-i18n-provider lang="ja">
|
||||
<media-text key="play"></media-text>
|
||||
<media-text key="Play"></media-text>
|
||||
</media-i18n-provider>
|
||||
```
|
||||
|
||||
@@ -20,8 +20,8 @@ import FrameworkCase from "@/components/docs/FrameworkCase.astro";
|
||||
|
||||
| Attribute | Description |
|
||||
| --- | --- |
|
||||
| `key` | Opaque translation key (`play`, `pause`, `timeRemainingPhrase`, …). |
|
||||
| `key` | English translation phrase (`Play`, `Pause`, `{duration} remaining`, …). |
|
||||
|
||||
Parametric keys are not yet supported on `<media-text>` — use `createTranslator` in script for interpolated strings.
|
||||
Parametric phrases are not yet supported on `<media-text>` — use `createTranslator` in script for interpolated strings.
|
||||
|
||||
</FrameworkCase>
|
||||
|
||||
@@ -8,14 +8,14 @@ import DocsLink from "@/components/docs/DocsLink.astro";
|
||||
|
||||
`registerI18n` merges a partial translation map into the process-wide registry for a locale tag. English defaults are registered by the i18n bundle. Call `registerI18n` for custom locales or to patch shipped packs before the player renders.
|
||||
|
||||
Import from `@videojs/html/i18n` or `@videojs/react/i18n`. Keys are opaque camelCase tokens (`play`, `pause`). See <DocsLink slug="concepts/i18n">Internationalization</DocsLink> and <DocsLink slug="reference/translations">`Translations`</DocsLink>.
|
||||
Import from `@videojs/html/i18n` or `@videojs/react/i18n`. Keys are the current English phrases (`Play`, `Pause`). See <DocsLink slug="concepts/i18n">Internationalization</DocsLink> and <DocsLink slug="reference/translations">`Translations`</DocsLink>.
|
||||
|
||||
```ts
|
||||
import { registerI18n } from '@videojs/react/i18n';
|
||||
|
||||
registerI18n('es', {
|
||||
play: 'Reproducir',
|
||||
pause: 'Pausar',
|
||||
Play: 'Reproducir',
|
||||
Pause: 'Pausar',
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
---
|
||||
title: TranslationParams
|
||||
description: Typed contract for translation keys and their placeholder arguments
|
||||
description: Typed contract for translation phrases and their placeholder arguments
|
||||
---
|
||||
|
||||
import DocsLink from '@/components/docs/DocsLink.astro';
|
||||
|
||||
`TranslationParams` maps every opaque translation key to its argument shape. Keys with `never` accept only `t('key')`. Keys with an object accept `t('key', { … })` with typed placeholder names.
|
||||
`TranslationParams` maps every current English translation phrase to its argument shape. Phrases with `never` accept only `t('Phrase')`. Phrases with an object accept `t('Phrase {value}', { … })` with typed placeholder names.
|
||||
|
||||
## Import
|
||||
|
||||
@@ -18,45 +18,45 @@ import type { TranslationParams } from '@videojs/html/i18n';
|
||||
|
||||
```ts
|
||||
type TranslationParams = {
|
||||
play: never;
|
||||
pause: never;
|
||||
seekForward: { seconds: number | string };
|
||||
timeRemainingPhrase: { duration: string };
|
||||
Play: never;
|
||||
Pause: never;
|
||||
'Seek forward {seconds} seconds': { seconds: number | string };
|
||||
'{duration} remaining': { duration: string };
|
||||
// …
|
||||
};
|
||||
```
|
||||
|
||||
English defaults and the full key list live in `packages/core/src/core/i18n/locales/en.ts`. The authoritative TypeScript map is `packages/core/src/core/i18n/types.ts`.
|
||||
English defaults and the full phrase list live in `packages/core/src/core/i18n/locales/en.ts`. The authoritative TypeScript map is `packages/core/src/core/i18n/types.ts`.
|
||||
|
||||
## Parametric keys
|
||||
## Parametric phrases
|
||||
|
||||
| Key | Placeholders | Example English value |
|
||||
| --- | --- | --- |
|
||||
| `seekForward` | `{seconds}` | `Seek forward {seconds} seconds` |
|
||||
| `seekBackward` | `{seconds}` | `Seek backward {seconds} seconds` |
|
||||
| `playbackRateAria` | `{rate}` | `Playback rate {rate}` |
|
||||
| `timeSliderValueTextRange` | `{current}`, `{duration}` | `{current} of {duration}` |
|
||||
| `timeRemainingPhrase` | `{duration}` | `{duration} remaining` |
|
||||
| `volumeSliderValueTextMuted` | `{percent}` | `{percent}, muted` |
|
||||
| `indicatorVolumeWithValue` | `{value}` | `Volume {value}` |
|
||||
| Phrase | Placeholders |
|
||||
| --- | --- |
|
||||
| `Seek forward {seconds} seconds` | `{seconds}` |
|
||||
| `Seek backward {seconds} seconds` | `{seconds}` |
|
||||
| `Playback rate {rate}` | `{rate}` |
|
||||
| `{current} of {duration}` | `{current}`, `{duration}` |
|
||||
| `{duration} remaining` | `{duration}` |
|
||||
| `{percent}, muted` | `{percent}` |
|
||||
| `Volume {value}` | `{value}` |
|
||||
|
||||
All other keys are plain strings with no parameters.
|
||||
All other phrases are plain strings with no parameters.
|
||||
|
||||
## Usage with Translator
|
||||
|
||||
```ts
|
||||
const t: Translator = createTranslator(translations, 'es');
|
||||
|
||||
t('play');
|
||||
t('seekForward', { seconds: 10 });
|
||||
t('timeRemainingPhrase', { duration: '1 minute' });
|
||||
t('Play');
|
||||
t('Seek forward {seconds} seconds', { seconds: 10 });
|
||||
t('{duration} remaining', { duration: '1 minute' });
|
||||
```
|
||||
|
||||
TypeScript rejects missing placeholders when defining <DocsLink slug="reference/translations">`Translations`</DocsLink> overlays:
|
||||
|
||||
```ts
|
||||
registerI18n('es', {
|
||||
seekForward: 'Adelantar', // error: missing {seconds}
|
||||
'Seek forward {seconds} seconds': 'Adelantar', // error: missing {seconds}
|
||||
});
|
||||
```
|
||||
|
||||
@@ -64,4 +64,4 @@ registerI18n('es', {
|
||||
|
||||
- <DocsLink slug="reference/translations">`Translations`</DocsLink>
|
||||
- <DocsLink slug="reference/translator">`Translator`</DocsLink>
|
||||
- <DocsLink slug="concepts/i18n">Internationalization</DocsLink>: Opaque keys overview
|
||||
- <DocsLink slug="concepts/i18n">Internationalization</DocsLink>: Phrase keys overview
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Translations
|
||||
description: Partial map of opaque translation keys to localized strings
|
||||
description: Partial map of English translation phrases to localized strings
|
||||
---
|
||||
|
||||
import DocsLink from '@/components/docs/DocsLink.astro';
|
||||
@@ -34,16 +34,16 @@ import type { Translations } from '@videojs/html/i18n';
|
||||
// or @videojs/react/i18n
|
||||
|
||||
const es = {
|
||||
play: 'Reproducir',
|
||||
pause: 'Pausa',
|
||||
seekForward: 'Adelantar {seconds} segundos',
|
||||
Play: 'Reproducir',
|
||||
Pause: 'Pausa',
|
||||
'Seek forward {seconds} seconds': 'Adelantar {seconds} segundos',
|
||||
} satisfies Partial<Translations>;
|
||||
|
||||
registerI18n('es', es);
|
||||
```
|
||||
|
||||
```tsx
|
||||
<I18nProvider locale="de" translations={{ play: 'Abspielen' }} />
|
||||
<I18nProvider locale="de" translations={{ Play: 'Abspielen' }} />
|
||||
```
|
||||
|
||||
Only supplied keys override lower layers. See <DocsLink slug="concepts/i18n">Internationalization</DocsLink> for merge priority.
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
---
|
||||
title: Translator
|
||||
description: Typed function that resolves opaque translation keys to localized strings
|
||||
description: Typed function that resolves English translation phrases to localized strings
|
||||
---
|
||||
|
||||
import DocsLink from '@/components/docs/DocsLink.astro';
|
||||
|
||||
`Translator` is the callable returned by <DocsLink slug="reference/create-translator">`createTranslator`</DocsLink> and <DocsLink slug="reference/use-translator">`useTranslator`</DocsLink>. It turns opaque keys from core controls into localized copy and interpolates `{placeholder}` tokens when params are required.
|
||||
`Translator` is the callable returned by <DocsLink slug="reference/create-translator">`createTranslator`</DocsLink> and <DocsLink slug="reference/use-translator">`useTranslator`</DocsLink>. It turns current English phrases from core controls into localized copy and interpolates `{placeholder}` tokens when params are required.
|
||||
|
||||
## Import
|
||||
|
||||
@@ -23,10 +23,10 @@ type Translator = <K extends keyof TranslationParams>(
|
||||
) => string;
|
||||
```
|
||||
|
||||
- Plain keys: `t('play')`
|
||||
- Parametric keys: `t('seekForward', { seconds: 10 })`
|
||||
- Plain phrases: `t('Play')`
|
||||
- Parametric phrases: `t('Seek forward {seconds} seconds', { seconds: 10 })`
|
||||
|
||||
Missing keys in the active map resolve to the key string (`'play'`) so partial locale packs degrade visibly during development.
|
||||
Missing phrases in the active map resolve to the source English (`'Play'`) so partial locale packs stay readable.
|
||||
|
||||
## Create manually
|
||||
|
||||
@@ -35,7 +35,7 @@ import { createTranslator, getI18nTranslations } from '@videojs/html/i18n';
|
||||
// or @videojs/react/i18n
|
||||
|
||||
const t = createTranslator(getI18nTranslations('pt-BR'), 'pt-BR');
|
||||
t('pause'); // localized or key fallback
|
||||
t('Pause'); // localized or English fallback
|
||||
```
|
||||
|
||||
## React hook
|
||||
@@ -45,11 +45,11 @@ import { useTranslator } from '@videojs/react/i18n';
|
||||
|
||||
function Label() {
|
||||
const t = useTranslator();
|
||||
return <span>{t('play')}</span>;
|
||||
return <span>{t('Play')}</span>;
|
||||
}
|
||||
```
|
||||
|
||||
Control components resolve keys from core `getLabel()` through `resolveControlLabel` / `resolveControlAttrs`. You rarely call `t()` directly unless building custom UI.
|
||||
Control components resolve phrases from core `getLabel()` through their framework adapters. You rarely call `t()` directly unless building custom UI.
|
||||
|
||||
## Related
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import FrameworkCase from "@/components/docs/FrameworkCase.astro";
|
||||
|
||||
<FrameworkCase frameworks={["react"]}>
|
||||
|
||||
`useTranslator` returns the translator from the nearest <DocsLink slug="reference/i18n-provider">`I18nProvider`</DocsLink>. Control components pass opaque keys from core `getLabel()` — for example `t('play')` and `t('seekForward', { seconds: 10 })`.
|
||||
`useTranslator` returns the translator from the nearest <DocsLink slug="reference/i18n-provider">`I18nProvider`</DocsLink>. Control components pass current English phrases from core `getLabel()` — for example `t('Play')` and `t('Seek forward {seconds} seconds', { seconds: 10 })`.
|
||||
|
||||
When no provider is mounted, the hook falls back to English registry strings so standalone demos do not throw.
|
||||
|
||||
|
||||
@@ -195,7 +195,7 @@ export const sidebar: Sidebar = [
|
||||
contents: [
|
||||
{ slug: 'reference/register-i18n', sidebarLabel: 'registerI18n' },
|
||||
{ slug: 'reference/get-i18n-translations', sidebarLabel: 'getI18nTranslations' },
|
||||
{ slug: 'reference/has-registered-i18n', sidebarLabel: 'hasRegisteredI18n' },
|
||||
{ slug: 'reference/has-registered-locale', sidebarLabel: 'hasRegisteredLocale' },
|
||||
{ slug: 'reference/on-i18n-registry-change', sidebarLabel: 'onI18nRegistryChange' },
|
||||
{ slug: 'reference/create-translator', sidebarLabel: 'createTranslator' },
|
||||
{
|
||||
|
||||
@@ -3,7 +3,7 @@ import { kebabCase } from 'es-toolkit/string';
|
||||
const UTIL_SLUG_OVERRIDES: Record<string, string> = {
|
||||
registerI18n: 'register-i18n',
|
||||
getI18nTranslations: 'get-i18n-translations',
|
||||
hasRegisteredI18n: 'has-registered-i18n',
|
||||
hasRegisteredLocale: 'has-registered-locale',
|
||||
onI18nRegistryChange: 'on-i18n-registry-change',
|
||||
createI18n: 'create-i18n',
|
||||
createTranslator: 'create-translator',
|
||||
|
||||
Reference in New Issue
Block a user