mirror of
https://github.com/shaka-project/shaka-player.git
synced 2026-06-14 15:56:38 +03:00
011749e95f
This changes the eslint rule to enforce a strict pattern for the argument comments. The comment must appear before the argument and must be /* foo= */. This still ignores line comments. Change-Id: I3afb01c65e1088eda13facb3aeeaa7595a2f5aee
507 lines
19 KiB
JavaScript
507 lines
19 KiB
JavaScript
/** @license
|
|
* Copyright 2016 Google LLC
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
describe('Localization', () => {
|
|
const Localization = shaka.ui.Localization;
|
|
|
|
// https://bit.ly/2PbzxlD
|
|
const DWARFISH = 'dwarfish';
|
|
const DWARFISH_NORTH = 'dwarfish-NORTH';
|
|
const DWARFISH_SOUTH = 'dwarfish-SOUTH';
|
|
|
|
const ELVISH = 'elvish';
|
|
const ELVISH_WOODLAND = 'elvish-WOODLAND';
|
|
|
|
const HALFLING = 'halfling';
|
|
const HALFLING_COMMON = 'halfling-COMMON';
|
|
const HALFLING_RIVER = 'halfling-RIVER';
|
|
const HALFLING_SHIRE = 'halfling-SHIRE';
|
|
|
|
describe('insert', () => {
|
|
const EN_US = 'en-US';
|
|
|
|
it('can add new data', () => {
|
|
/** @type {!shaka.ui.Localization} */
|
|
const localization = new Localization(EN_US);
|
|
localization.insert(EN_US, new Map([
|
|
['hello', 'howdy'],
|
|
['good-bye', 'cheerio'],
|
|
]));
|
|
|
|
expect(localization.resolve('hello')).toBe('howdy');
|
|
expect(localization.resolve('good-bye')).toBe('cheerio');
|
|
});
|
|
|
|
it('can replace old data when adding new data', () => {
|
|
/** @type {!shaka.ui.Localization} */
|
|
const localization = new Localization(EN_US);
|
|
localization.insert(EN_US, new Map([
|
|
['hello', 'howdy'],
|
|
['good-bye', 'cheerio'],
|
|
]));
|
|
|
|
expect(localization.resolve('hello')).toBe('howdy');
|
|
expect(localization.resolve('good-bye')).toBe('cheerio');
|
|
|
|
localization.insert(EN_US, new Map([
|
|
['good-bye', 'farewell'],
|
|
['thank-you', 'thank-you'],
|
|
]));
|
|
|
|
expect(localization.resolve('hello')).toBe('howdy');
|
|
expect(localization.resolve('good-bye')).toBe('farewell');
|
|
expect(localization.resolve('thank-you')).toBe('thank-you');
|
|
});
|
|
|
|
it('can keep old data when adding new', () => {
|
|
const USE_OLD = Localization.ConflictResolution.USE_OLD;
|
|
|
|
/** @type {!shaka.ui.Localization} */
|
|
const localization = new Localization(EN_US);
|
|
localization.insert(EN_US, new Map([
|
|
['hello', 'howdy'],
|
|
['good-bye', 'cheerio'],
|
|
]));
|
|
|
|
expect(localization.resolve('hello')).toBe('howdy');
|
|
expect(localization.resolve('good-bye')).toBe('cheerio');
|
|
|
|
localization.insert(EN_US, new Map([
|
|
['hello', 'greetings'],
|
|
['good-bye', 'farewell'],
|
|
['thank-you', 'thank-you'],
|
|
]), USE_OLD);
|
|
|
|
// Nothing should have changed.
|
|
expect(localization.resolve('hello')).toBe('howdy');
|
|
expect(localization.resolve('good-bye')).toBe('cheerio');
|
|
expect(localization.resolve('thank-you')).toBe('thank-you');
|
|
});
|
|
});
|
|
|
|
describe('locale fallback', () => {
|
|
const KEY = 'KEY';
|
|
|
|
const FALLBACK = 'FALLBACK';
|
|
const FALLBACK_VALUE = 'FALLBACK VALUE';
|
|
|
|
const ELVISH_VALUE = 'ELVISH VALUE';
|
|
|
|
const HALFLING_COMMON_VALUE = 'HALFLING-COMMON VALUE';
|
|
const HALFLING_SHIRE_VALUE = 'HALFLING-SHIRE VALUE';
|
|
|
|
/** @type {!shaka.ui.Localization} */
|
|
let localization;
|
|
|
|
const insert = (locale, value) => {
|
|
localization.insert(locale, new Map([[KEY, value]]));
|
|
};
|
|
|
|
const testLocales = (locales, expectedValue) => {
|
|
localization.changeLocale(locales);
|
|
const value = localization.resolve(KEY);
|
|
expect(value).toBe(expectedValue);
|
|
};
|
|
|
|
beforeEach(() => {
|
|
localization = new Localization(FALLBACK);
|
|
|
|
// Insert translations to test various scenarios below:
|
|
insert(FALLBACK, FALLBACK_VALUE);
|
|
insert(ELVISH, ELVISH_VALUE);
|
|
insert(HALFLING_COMMON, HALFLING_COMMON_VALUE);
|
|
insert(HALFLING_SHIRE, HALFLING_SHIRE_VALUE);
|
|
});
|
|
|
|
it('resorts to final fallback for one unknown locale', () => {
|
|
// For one locale we don't have translations for, go to the fallback.
|
|
testLocales([DWARFISH_NORTH], FALLBACK_VALUE);
|
|
});
|
|
|
|
it('resorts to final fallback for multiple unknown locales', () => {
|
|
// For multiple locales in which we don't have translations, go to the
|
|
// fallback.
|
|
testLocales([
|
|
DWARFISH_NORTH,
|
|
DWARFISH_SOUTH,
|
|
], FALLBACK_VALUE);
|
|
});
|
|
|
|
it('prefers a known locale from the list instead of final fallback', () => {
|
|
// If we have a locale in the list for which we _do_ have translations,
|
|
// expect to see the translated value.
|
|
testLocales([
|
|
DWARFISH_NORTH,
|
|
DWARFISH_SOUTH,
|
|
ELVISH,
|
|
], ELVISH_VALUE);
|
|
});
|
|
|
|
it('prefers the first known locale from the list', () => {
|
|
// If we have multiple locales in the list for which we _do_ have
|
|
// translations, expect to see the translated value from the first one.
|
|
testLocales([
|
|
DWARFISH_NORTH,
|
|
DWARFISH_SOUTH,
|
|
HALFLING_COMMON,
|
|
ELVISH,
|
|
], HALFLING_COMMON_VALUE);
|
|
});
|
|
|
|
it('finds translations from the parent locale', () => {
|
|
// If we have a locale in the list for which we have a region-less
|
|
// translation, expect to see the translated value.
|
|
testLocales([ELVISH_WOODLAND], ELVISH_VALUE);
|
|
});
|
|
|
|
it('finds translations from a locale with a different region', () => {
|
|
// If there's a locale in the list for which we have translations in a
|
|
// sibling locale (same language, different region), expect to see that
|
|
// value. Common is chosen over shire because equivalent-distance locales
|
|
// are alphabetically sorted to break ties.
|
|
testLocales([HALFLING_RIVER], HALFLING_COMMON_VALUE);
|
|
});
|
|
|
|
it('finds translations from a child locale', () => {
|
|
// If there's a locale in the list for which we have translations in a
|
|
// child locale (same language, but for a specific region), expect to see
|
|
// that value. Common is chosen over shire because equivalent-distance
|
|
// locales are alphabetically sorted to break ties.
|
|
testLocales([HALFLING], HALFLING_COMMON_VALUE);
|
|
});
|
|
|
|
it('prefers a relative of an earlier locale to an exact later one', () => {
|
|
// If we have multiple locales in the list, and an earlier one has
|
|
// relatives with translations, expect to see that chosen over an exact
|
|
// match later in the list.
|
|
testLocales([
|
|
HALFLING,
|
|
ELVISH,
|
|
], HALFLING_COMMON_VALUE);
|
|
});
|
|
});
|
|
|
|
describe('unknown locales event', () => {
|
|
it('fires when we change to a locale we have not loaded', () => {
|
|
const events = [];
|
|
|
|
const localization = new Localization(/* fallback= */ HALFLING_COMMON);
|
|
collectEvents(localization, Localization.UNKNOWN_LOCALES, events);
|
|
|
|
localization.insert(HALFLING_COMMON, new Map());
|
|
localization.changeLocale([ELVISH_WOODLAND]);
|
|
|
|
expect(events.length).toBe(1);
|
|
expect(events[0].locales).toEqual([ELVISH_WOODLAND]);
|
|
});
|
|
|
|
|
|
it('will not fire after we add the locale', () => {
|
|
const events = [];
|
|
|
|
const localization = new Localization(/* fallback= */ HALFLING_COMMON);
|
|
collectEvents(localization, Localization.UNKNOWN_LOCALES, events);
|
|
|
|
// We should see an event telling us that both elvish and dwarfish are
|
|
// missing.
|
|
localization.insert(HALFLING_COMMON, new Map());
|
|
localization.changeLocale([ELVISH_WOODLAND, DWARFISH_NORTH]);
|
|
|
|
expect(events.length).toBe(1);
|
|
expect(events[0].locales).toEqual([ELVISH_WOODLAND, DWARFISH_NORTH]);
|
|
|
|
// We should see an event telling us that dwarfish is still missing.
|
|
localization.insert(ELVISH_WOODLAND, new Map());
|
|
localization.changeLocale([ELVISH_WOODLAND, DWARFISH_NORTH]);
|
|
|
|
expect(events.length).toBe(2);
|
|
expect(events[0].locales).toEqual([ELVISH_WOODLAND, DWARFISH_NORTH]);
|
|
expect(events[1].locales).toEqual([DWARFISH_NORTH]);
|
|
|
|
// There should be no more events now that we added the last language.
|
|
localization.insert(DWARFISH_NORTH, new Map());
|
|
localization.changeLocale([ELVISH_WOODLAND, DWARFISH_NORTH]);
|
|
|
|
expect(events.length).toBe(2);
|
|
expect(events[0].locales).toEqual([ELVISH_WOODLAND, DWARFISH_NORTH]);
|
|
expect(events[1].locales).toEqual([DWARFISH_NORTH]);
|
|
});
|
|
});
|
|
|
|
describe('unknown localization event', () => {
|
|
const HOW_ARE_YOU = 'how are you';
|
|
|
|
const HALFLING_COMMON_MAP = new Map().set(
|
|
HOW_ARE_YOU, 'How ye this topa the mornin?');
|
|
const HALFLING_SHIRE_MAP = new Map().set(
|
|
HOW_ARE_YOU, 'How be the day treating ya?');
|
|
const DWARFISH_MAP = new Map().set(
|
|
HOW_ARE_YOU, 'You alive?');
|
|
const DWARFISH_NORTH_MAP = new Map().set(
|
|
HOW_ARE_YOU, 'Is the fire alive in ye soul?');
|
|
const DWARFISH_SOUTH_MAP = new Map().set(
|
|
HOW_ARE_YOU, 'You dead yet?');
|
|
|
|
/** @type {!shaka.ui.Localization} */
|
|
let localization;
|
|
|
|
beforeEach(() => {
|
|
localization = new shaka.ui.Localization(HALFLING_COMMON);
|
|
|
|
// Insert every locale into the system but leave them empty. Each test
|
|
// will add entries as they need them.
|
|
const emptyMap = new Map();
|
|
localization.insert(DWARFISH, emptyMap);
|
|
localization.insert(DWARFISH_NORTH, emptyMap);
|
|
localization.insert(DWARFISH_SOUTH, emptyMap);
|
|
localization.insert(HALFLING_COMMON, emptyMap);
|
|
localization.insert(HALFLING_SHIRE, emptyMap);
|
|
});
|
|
|
|
it('will not fire when key is found in preferred', () => {
|
|
localization.insert(DWARFISH_NORTH, DWARFISH_NORTH_MAP);
|
|
localization.changeLocale([DWARFISH_NORTH]);
|
|
|
|
const events = [];
|
|
collectEvents(localization, Localization.UNKNOWN_LOCALIZATION, events);
|
|
|
|
// We expect to see a non-empty string returned and to see NO "missing
|
|
// localization" events.
|
|
expect(localization.resolve(HOW_ARE_YOU)).toBeTruthy();
|
|
expect(events.length).toBe(0);
|
|
});
|
|
|
|
it('will not fire when key is found in base', () => {
|
|
localization.insert(DWARFISH, DWARFISH_MAP);
|
|
localization.changeLocale([DWARFISH_NORTH]);
|
|
|
|
const events = [];
|
|
collectEvents(localization, Localization.UNKNOWN_LOCALIZATION, events);
|
|
|
|
// We expect to see a non-empty string returned and to see NO "missing
|
|
// localization" events.
|
|
expect(localization.resolve(HOW_ARE_YOU)).toBeTruthy();
|
|
expect(events.length).toBe(0);
|
|
});
|
|
|
|
it('will not fire when key is found in sibling', () => {
|
|
localization.insert(DWARFISH_SOUTH, DWARFISH_SOUTH_MAP);
|
|
localization.changeLocale([DWARFISH_NORTH]);
|
|
|
|
const events = [];
|
|
collectEvents(localization, Localization.UNKNOWN_LOCALIZATION, events);
|
|
|
|
// We expect to see a non-empty string returned and to see NO "missing
|
|
// localization" events.
|
|
expect(localization.resolve(HOW_ARE_YOU)).toBeTruthy();
|
|
expect(events.length).toBe(0);
|
|
});
|
|
|
|
it('will not fire when key is found in fallback', () => {
|
|
localization.insert(HALFLING_COMMON, HALFLING_COMMON_MAP);
|
|
localization.changeLocale([DWARFISH_NORTH]);
|
|
|
|
const events = [];
|
|
collectEvents(localization, Localization.UNKNOWN_LOCALIZATION, events);
|
|
|
|
// We expect to see a non-empty string returned and to see NO "missing
|
|
// localization" events.
|
|
expect(localization.resolve(HOW_ARE_YOU)).toBeTruthy();
|
|
expect(events.length).toBe(0);
|
|
});
|
|
|
|
it('fires when key is not found', () => {
|
|
localization.changeLocale([DWARFISH_NORTH]);
|
|
|
|
const events = [];
|
|
collectEvents(localization, Localization.UNKNOWN_LOCALIZATION, events);
|
|
|
|
// When nothing is found an empty string should be returned and we should
|
|
// see a "missing localization" event.
|
|
expect(localization.resolve(HOW_ARE_YOU)).toBe('');
|
|
expect(events.length).toBe(1);
|
|
});
|
|
|
|
// This test is similar to "missing from everything", but the difference
|
|
// here is that the entry can be found in a locale that is not part of
|
|
// search.
|
|
it('fires when key is not found in fallback, siblings, base, or preferred',
|
|
() => {
|
|
localization.insert(HALFLING_SHIRE, HALFLING_SHIRE_MAP);
|
|
localization.changeLocale([DWARFISH_NORTH]);
|
|
|
|
const events = [];
|
|
collectEvents(
|
|
localization, Localization.UNKNOWN_LOCALIZATION, events);
|
|
|
|
// When nothing is found an empty string should be returned and we
|
|
// should see a "missing localization" event.
|
|
expect(localization.resolve(HOW_ARE_YOU)).toBe('');
|
|
expect(events.length).toBe(1);
|
|
});
|
|
});
|
|
|
|
// The "missing localizations event" is fired when all preferred locales do
|
|
// not have the requested localization but a related locale does have the
|
|
// requested localization
|
|
describe('missing localizations event', () => {
|
|
it('fires when key/value is missing from preferred but found in fallback',
|
|
() => {
|
|
// Initialize the localization system so that we have an entry for
|
|
// "hello" in our fallback, but not in our preferred locale.
|
|
const localization = new Localization(HALFLING_COMMON);
|
|
localization.insert(HALFLING_COMMON, new Map([
|
|
['hello', 'Hallo! Hallo! And who may you be?'],
|
|
]));
|
|
localization.insert(ELVISH_WOODLAND, new Map());
|
|
|
|
const events = [];
|
|
collectEvents(
|
|
localization, Localization.MISSING_LOCALIZATIONS, events);
|
|
|
|
// Change locales should cause the missing localizations event to fire
|
|
// and report that we are missing an entry for "hello".
|
|
localization.changeLocale([ELVISH_WOODLAND]);
|
|
|
|
// We should be told that we are missing an entry for "hello" because
|
|
// it was in the fallback (HALFLING) but not our preferred language
|
|
// (EVLISH).
|
|
expect(events.length).toBe(1);
|
|
expect(events[0].locales).toEqual([ELVISH_WOODLAND]);
|
|
expect(events[0].missing).toEqual(['hello']);
|
|
});
|
|
|
|
it('fires when key/value is missing from preferred but found in base',
|
|
() => {
|
|
// Initialize the localization system so that we have an entry for
|
|
// "Best Wishes" in our base language, but not in our preferred
|
|
// locale.
|
|
const localization = new Localization(HALFLING_COMMON);
|
|
localization.insert(ELVISH_WOODLAND, new Map());
|
|
localization.insert(ELVISH, new Map([
|
|
['Best Wishes', 'Merin sa haryalye alasse'],
|
|
]));
|
|
|
|
const events = [];
|
|
collectEvents(
|
|
localization, Localization.MISSING_LOCALIZATIONS, events);
|
|
|
|
// Change locales should cause the missing localizations event to fire
|
|
// and report that we are missing an entry for "Best Wishes".
|
|
localization.changeLocale([ELVISH_WOODLAND]);
|
|
|
|
// We should be told that we are missing an entry for "Best Wishes"
|
|
// because it was in the base (ELVISH) but not our preferred language
|
|
// (EVLISH_WOODLAND).
|
|
expect(events.length).toBe(1);
|
|
expect(events[0].locales).toEqual([ELVISH_WOODLAND]);
|
|
expect(events[0].missing).toEqual(['Best Wishes']);
|
|
});
|
|
|
|
it('fires when key/value is missing from preferred but found in sibling',
|
|
() => {
|
|
// Initialize the localization system so that we have an entry for
|
|
// "Do you understand" in a language that shares a base language with
|
|
// our preferred locale, but not in our preferred locale.
|
|
const localization = new Localization(ELVISH_WOODLAND);
|
|
localization.insert(HALFLING_COMMON, new Map());
|
|
localization.insert(HALFLING_SHIRE, new Map([
|
|
['Do you understand', 'If you take my meaning.'],
|
|
]));
|
|
|
|
const events = [];
|
|
collectEvents(
|
|
localization, Localization.MISSING_LOCALIZATIONS, events);
|
|
|
|
// Change locales should cause the missing localizations event to fire
|
|
// and report that we are missing an entry for "Best Wishes".
|
|
localization.changeLocale([HALFLING_COMMON]);
|
|
|
|
// We should be told that we are missing an entry for "Do you
|
|
// understand" because it was in a sibling locale (HALFLING_SHIRE)
|
|
// but not our preferred language (HALFLING_COMMON).
|
|
expect(events.length).toBe(1);
|
|
expect(events[0].locales).toEqual([HALFLING_COMMON]);
|
|
expect(events[0].missing).toEqual(['Do you understand']);
|
|
});
|
|
|
|
it('fires when key/value is missing from some preferred languages',
|
|
() => {
|
|
// Initialize the localization system so that we have an entry for
|
|
// "may your forge burn bright" in our second preference but not our
|
|
// first.
|
|
const localization = new Localization(HALFLING_COMMON);
|
|
localization.insert(HALFLING_COMMON, new Map());
|
|
localization.insert(ELVISH_WOODLAND, new Map());
|
|
localization.insert(DWARFISH_NORTH, new Map([
|
|
['may your forge burn bright', 'tan menu selek lanun khun'],
|
|
]));
|
|
|
|
const events = [];
|
|
collectEvents(
|
|
localization, Localization.MISSING_LOCALIZATIONS, events);
|
|
|
|
// Changing locales should not fire the missing localization event
|
|
// because the localization for "may your forge burn bright" can
|
|
// be found in our secondary preferred language.
|
|
localization.changeLocale([ELVISH_WOODLAND, DWARFISH_NORTH]);
|
|
|
|
// There should have no missing localization events.
|
|
expect(events.length).toBe(1);
|
|
expect(events[0].locales).toEqual([ELVISH_WOODLAND, DWARFISH_NORTH]);
|
|
expect(events[0].missing).toEqual(['may your forge burn bright']);
|
|
});
|
|
});
|
|
|
|
describe('locale changed event', () => {
|
|
it('fires when locale changes', () => {
|
|
const localization = new Localization(HALFLING_COMMON);
|
|
|
|
const events = [];
|
|
collectEvents(localization, Localization.LOCALE_CHANGED, events);
|
|
|
|
// We are going from nothing to something, we should see an event.
|
|
localization.changeLocale([DWARFISH_SOUTH]);
|
|
expect(events.length).toBe(1);
|
|
|
|
// We are changing from SOUTH to NORTH, we should see another event.
|
|
localization.changeLocale([DWARFISH_NORTH]);
|
|
expect(events.length).toBe(2);
|
|
});
|
|
|
|
it('fires when changing to the same locale', () => {
|
|
const localization = new Localization(HALFLING_COMMON);
|
|
|
|
const events = [];
|
|
collectEvents(localization, Localization.LOCALE_CHANGED, events);
|
|
|
|
// We are going from nothing to something, we should see an event.
|
|
localization.changeLocale([DWARFISH_SOUTH]);
|
|
expect(events.length).toBe(1);
|
|
|
|
// We are going to ask to go our current locale, even through
|
|
// conceptually this would be a no-op, the event should still fire.
|
|
localization.changeLocale([DWARFISH_SOUTH]);
|
|
expect(events.length).toBe(2);
|
|
});
|
|
});
|
|
|
|
/**
|
|
* Listen to |localization| for specific events and save them in |out|.
|
|
*
|
|
* @param {!shaka.ui.Localization} localization
|
|
* @param {string} eventName
|
|
* @param {!Array.<!shaka.util.FakeEvent>} out
|
|
*/
|
|
function collectEvents(localization, eventName, out) {
|
|
const onEvent = (event) => {
|
|
const fakeEvent = /** @type {!shaka.util.FakeEvent} */ (event);
|
|
out.push(fakeEvent);
|
|
};
|
|
|
|
localization.addEventListener(eventName, onEvent);
|
|
}
|
|
});
|