diff --git a/docs/guides/languages.md b/docs/guides/languages.md index 94de374957..61f00542b9 100644 --- a/docs/guides/languages.md +++ b/docs/guides/languages.md @@ -37,7 +37,7 @@ Video.js uses key/value object dictionaries in JSON form. A sample dictionary fo ``` Notes: - + - The file name should always be in the format `XX.json`, where `XX` is the two letter value of the language reported to the browser (for options see the bottom of this document). - For automatic inclusion at build time, add your language file to the `/lang` directory (see 'Adding Languages to Video.js below'). @@ -45,7 +45,7 @@ Adding Languages to Video.js ---------------------------- Additional language support can be added to Video.js in multiple ways. -1. Create language scripts out of your JSON objects by using our custom grunt task `vjslanguages`. This task is automatically run as part of the default grunt task in Video.JS, but can be configured to match your `src`/`dist` directories if different. Once these scripts are created, just add them to your DOM like any other script. +1. Create language scripts out of your JSON objects by using our custom grunt task `vjslanguages`. This task is automatically run as part of the default grunt task in Video.JS, but can be configured to match your `src`/`dist` directories if different. Once these scripts are created, just add them to your DOM like any other script. NOTE: These need to be added after the core Video.js script. @@ -122,6 +122,24 @@ During a Video.js player instantiation you can force it to localize to a specifi ``` +Determining Player Language +--------------------------- + +The player language is set to one of the following in descending priority + +* The language set in setup options as above +* The document language (`lang` attribute of the `html` element) +* Browser language preference +* 'en' + +That can be overridden after instantiation with `language('fr')`. + +Language selection +------------------ + +* Language codes are considered case-insensitively (`en-US` == `en-us`). +* If there is no match for a language code with a subcode (`en-us`), a match for the primary code (`en`) is used if available. + Localization in Plugins ----------------------- @@ -133,7 +151,7 @@ var details = '
' + player.localize('Technical de Language Codes -------------- -The following is a list of official language codes. +The following is a list of official language codes. **NOTE:** For supported language translations, please see the [Languages Folder (/lang)](../../lang) folder located in the project root. @@ -180,10 +198,10 @@ The following is a list of official language codes. fjFiji fiFinnish - + - + @@ -223,10 +241,10 @@ The following is a list of official language codes.
frFrench
fyFrisian
loLaothian
laLatin
- + - + @@ -266,10 +284,10 @@ The following is a list of official language codes.
lvLatvian (Lettish)
liLimburgish ( Limburger)
iiSichuan Yi
sdSindhi
- + - + @@ -307,7 +325,7 @@ The following is a list of official language codes.
siSinhalese
ssSiswati
yoYoruba
zuZulu
- + diff --git a/src/js/component.js b/src/js/component.js index 52b8d149cd..21e8140740 100644 --- a/src/js/component.js +++ b/src/js/component.js @@ -216,13 +216,21 @@ class Component { } localize(string) { - let lang = this.player_.language(); + let lang = ('' + this.player_.language()).toLowerCase(); + let primaryCode = lang.split('-')[0]; let languages = this.player_.languages(); - if (languages && languages[lang] && languages[lang][string]) { + if (!languages) { + return string; + } + if (languages[lang] && languages[lang][string]) { return languages[lang][string]; } - + if (primaryCode !== lang && + languages[primaryCode] && + languages[primaryCode][string]) { + return languages[primaryCode][string]; + } return string; } diff --git a/src/js/player.js b/src/js/player.js index 2cd47b12e3..7523924df4 100644 --- a/src/js/player.js +++ b/src/js/player.js @@ -104,7 +104,17 @@ class Player extends Component { this.language_ = options['language'] || Options['language']; // Update Supported Languages - this.languages_ = options['languages'] || Options['languages']; + if (options['languages']) { + // Normalise player option languages to lowercase + let languagesToLower = {}; + + Object.getOwnPropertyNames(options['languages']).forEach(function(name) { + languagesToLower[name.toLowerCase()] = options['languages'][name]; + }); + this.languages_ = languagesToLower; + } else { + this.languages_ = Options['languages']; + } // Cache for video property values. this.cache_ = {}; @@ -2105,9 +2115,11 @@ class Player extends Component { /** * Get the player's language dictionary + * Merge every time, because a newly added plugin might call videojs.addLanguage() at any time + * Languages specified directly in the player options have precedence */ languages() { - return this.languages_; + return mergeOptions(Options['languages'], this.languages_); } toJSON() { diff --git a/src/js/video.js b/src/js/video.js index 563eb858c3..67f4a34537 100644 --- a/src/js/video.js +++ b/src/js/video.js @@ -142,7 +142,8 @@ videojs.plugin = plugin; * @return {Object} The resulting global languages dictionary object */ videojs.addLanguage = function(code, data){ - if(Options['languages'][code] !== undefined) { + code = ('' + code).toLowerCase(); + if(typeof Options['languages'][code] !== 'undefined') { Options['languages'][code] = mergeOptions(Options['languages'][code], data); } else { Options['languages'][code] = data; diff --git a/test/unit/player.test.js b/test/unit/player.test.js index a7e00c1e5b..b1ede564ac 100644 --- a/test/unit/player.test.js +++ b/test/unit/player.test.js @@ -791,3 +791,25 @@ test('should have a sensible toJSON that is equivalent to player.options', funct deepEqual(player2.toJSON(), popts, 'no circular references'); }); + +test('should ignore case in language codes and try primary code', function() { +expect(3); + + var player = TestHelpers.makePlayer({ + 'languages': { + 'en-gb': { + 'Good': 'Brilliant' + }, + 'EN': { + 'Good': 'Awesome', + 'Error': 'Problem' + } + } + }); + + player.language('en-gb'); + strictEqual(player.localize('Good'), 'Brilliant', 'Used subcode specific localisation'); + strictEqual(player.localize('Error'), 'Problem', 'Used primary code localisation'); + player.language('en-GB'); + strictEqual(player.localize('Good'), 'Brilliant', 'Ignored case'); +}); diff --git a/test/unit/video.test.js b/test/unit/video.test.js index 59e105c84b..e4f6447f4d 100644 --- a/test/unit/video.test.js +++ b/test/unit/video.test.js @@ -46,6 +46,17 @@ test('should add the value to the languages object', function() { deepEqual(result[code], Options['languages'][code], 'should also match'); }); +test('should add the value to the languages object with lower case lang code', function() { + var code, data, result; + + code = 'DE'; + data = {'Hello': 'Guten Tag'}; + result = videojs.addLanguage(code, data); + + ok(Options['languages'][code.toLowerCase()], 'should exist'); + equal(Options['languages'][code.toLowerCase()], data, 'should match'); + deepEqual(result[code.toLowerCase()], Options['languages'][code.toLowerCase()], 'should also match'); +}); test('should expose plugin registry function', function() { var pluginName, pluginFunction, player;