|
4 | 4 | */ |
5 | 5 |
|
6 | 6 | import { translate as t } from '@nextcloud/l10n' |
| 7 | +import { getCanonicalLocale } from '@nextcloud/l10n' |
7 | 8 |
|
8 | 9 | /** |
9 | 10 | * Plyr `i18n` option so the player controls and menus |
@@ -49,3 +50,48 @@ export const plyrTranslations: Record<string, string> = { |
49 | 50 | enabled: t('viewer', 'Enabled'), |
50 | 51 | advertisement: t('viewer', 'Ad'), |
51 | 52 | } |
| 53 | + |
| 54 | +/** |
| 55 | + * Plyr renders speed values via a plain template literal (`` `${speed}×` ``), |
| 56 | + * which always uses a `.` decimal separator regardless of locale — so German |
| 57 | + * shows `1.5×` instead of `1,5×`. Plyr exposes no hook for this, so we |
| 58 | + * re-format the rendered labels using the user's locale. |
| 59 | + * |
| 60 | + * The speed panel's id always ends in `-speed`. Each entry is a |
| 61 | + * `button[role="menuitemradio"]` carrying the numeric speed in its `value` |
| 62 | + * attribute (the source of truth). The home-pane `.plyr__menu__value` badge |
| 63 | + * shows the current speed as a bare `<number>×` string, which we match by |
| 64 | + * pattern so we never touch the quality/captions badges. |
| 65 | + * |
| 66 | + * @param root the Plyr root element to localize labels within |
| 67 | + */ |
| 68 | +export function localizeSpeedLabels(root: ParentNode): void { |
| 69 | + const formatter = new Intl.NumberFormat(getCanonicalLocale()) |
| 70 | + const speedLabel = (value: number): string => |
| 71 | + value === 1 ? t('viewer', 'Normal') : `${formatter.format(value)}×` |
| 72 | + |
| 73 | + // Speed submenu radio items, scoped to the speed panel so we don't touch |
| 74 | + // quality (e.g. "1080") or captions entries. |
| 75 | + const items = root.querySelectorAll<HTMLButtonElement>( |
| 76 | + '.plyr__menu__container [id$="-speed"] [role="menuitemradio"]', |
| 77 | + ) |
| 78 | + items.forEach((item) => { |
| 79 | + const value = Number.parseFloat(item.value) |
| 80 | + if (Number.isNaN(value)) { |
| 81 | + return |
| 82 | + } |
| 83 | + const label = item.querySelector('span') |
| 84 | + if (label) { |
| 85 | + label.textContent = speedLabel(value) |
| 86 | + } |
| 87 | + }) |
| 88 | + |
| 89 | + // Home-pane badge showing the current speed (e.g. "Speed: 1,5×"). Match the |
| 90 | + // bare "<number>×" form so quality/captions badges are left untouched. |
| 91 | + root.querySelectorAll<HTMLElement>('.plyr__menu__value').forEach((badge) => { |
| 92 | + const match = /^(\d+(?:\.\d+)?)×$/.exec((badge.textContent ?? '').trim()) |
| 93 | + if (match) { |
| 94 | + badge.textContent = `${formatter.format(Number.parseFloat(match[1]))}×` |
| 95 | + } |
| 96 | + }) |
| 97 | +} |
0 commit comments