Skip to content

Commit

Permalink
feat: detect language from html lang attributes and navigator.languages
Browse files Browse the repository at this point in the history
  • Loading branch information
wangcheng committed Mar 27, 2019
1 parent f7b4c22 commit 9ffffc0
Show file tree
Hide file tree
Showing 7 changed files with 130 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
import {MessageProvider, InternalContext} from '../../contexts/Message'
import {PositionProvider} from '../../contexts/Position'
import {ObjectFitProvider, VALID_FIT} from '../../contexts/ObjectFit'
import {LanguageContext} from '../../contexts/Language'
import {LanguageProvider} from '../../contexts/Language'

const PlayerContainer = ({
standalone,
Expand All @@ -24,15 +24,15 @@ const PlayerContainer = ({
children,
initialObjectFit = 'contain',
useMSE,
language = 'en',
language,
}) => (
<ObjectFitProvider initialObjectFit={initialObjectFit}>
<PositionProvider shouldObserveResize={shouldObserveResize}>
<MessageProvider id={id} enableCrossWindow={standalone}>
<InternalContext.Consumer>
{({emitEvent, subscribeAction}) => (
<VideoSourceProvider onEvent={emitEvent} sources={sources} id={id}>
<LanguageContext.Provider value={language}>
<LanguageProvider language={language}>
<VideoSourceContext.Consumer>
{({currentSrc}) => (
<Player
Expand All @@ -49,7 +49,7 @@ const PlayerContainer = ({
)}
</VideoSourceContext.Consumer>
{children}
</LanguageContext.Provider>
</LanguageProvider>
</VideoSourceProvider>
)}
</InternalContext.Consumer>
Expand Down
10 changes: 6 additions & 4 deletions packages/griffith/src/components/TranslatedText/strings.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import SUPPORTED_LANGUAGES from '../../contexts/Language/supportedLanguages'

export default {
en: {
[SUPPORTED_LANGUAGES.EN]: {
'quality-auto': 'Auto',
'quality-ld': 'LD',
'quality-sd': 'SD',
'quality-hd': 'HD',
'action-enter-fullscreen': 'Fullscreen',
'action-exit-fullscreen': 'Exit Fullscreen',
},
ja: {
[SUPPORTED_LANGUAGES.JA]: {
'quality-auto': '自動',
'quality-ld': '低画質',
'quality-sd': '標準画質',
Expand All @@ -16,7 +18,7 @@ export default {
'action-exit-fullscreen': '全画面終了',
},
// covers zh-Hans-CN and zh-Hans-SG
'zh-Hans': {
[SUPPORTED_LANGUAGES.ZH_HANS]: {
'quality-auto': '自动',
'quality-ld': '低清',
'quality-sd': '标清',
Expand All @@ -25,7 +27,7 @@ export default {
'action-exit-fullscreen': '退出全屏',
},
// covers zh-Hant-HK and zh-Hant-TW
'zh-Hant': {
[SUPPORTED_LANGUAGES.ZH_HANT]: {
'quality-auto': '自動',
'quality-ld': '低畫質',
'quality-sd': '標準畫質',
Expand Down
39 changes: 39 additions & 0 deletions packages/griffith/src/contexts/Language/LanguageProvider.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React from 'react'
import PropTypes from 'prop-types'
import LanguageContext from './LanguageContext'
import guessLanguage from './guessLanguage'
import SUPPORTED_LANGUAGES from './supportedLanguages'

const VALID_LANGUAGES = Object.keys(SUPPORTED_LANGUAGES)

const isValid = language => VALID_LANGUAGES.includes(language)

export default class LanguageProvider extends React.Component {
static propTypes = {
language: PropTypes.oneOf(VALID_LANGUAGES),
}

state = {
language: isValid(this.props.language)
? this.props.language
: SUPPORTED_LANGUAGES.EN,
}

componentDidMount() {
if (!isValid(this.props.language)) {
// detect language from html lang attributes and navigator.languages
const htmlLanguage = document.documentElement.getAttribute('lang')
const navigatorLanguages = navigator.languages || [navigator.language]
const languageList = [htmlLanguage, ...navigatorLanguages]
this.setState({language: guessLanguage(languageList)})
}
}

render() {
return (
<LanguageContext.Provider value={this.state.language}>
{this.props.children}
</LanguageContext.Provider>
)
}
}
35 changes: 35 additions & 0 deletions packages/griffith/src/contexts/Language/guessLanguage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import SUPPORTED_LANGUAGES from './supportedLanguages'

const KEY_WORDS = [
['en', SUPPORTED_LANGUAGES.EN],
['ja', SUPPORTED_LANGUAGES.JA],

['hant', SUPPORTED_LANGUAGES.ZH_HANT],
['hans', SUPPORTED_LANGUAGES.ZH_HANS],

['hk', SUPPORTED_LANGUAGES.ZH_HANT],
['tw', SUPPORTED_LANGUAGES.ZH_HANT],

['cn', SUPPORTED_LANGUAGES.ZH_HANS],
['sg', SUPPORTED_LANGUAGES.ZH_HANS],

['zh', SUPPORTED_LANGUAGES.ZH_HANS], // prefer Simplified Chinese to Traditional if not specified
]

function matchKeyword(langCode) {
const found = KEY_WORDS.find(([keyword]) => langCode.includes(keyword))
return found ? found[1] : null
}

function guessLanguage(languageList) {
const list = languageList.filter(Boolean).map(s => s.toLocaleLowerCase())
for (let i = 0; i < list.length; i = i + 1) {
const matchedSupportedLanguage = matchKeyword(list[i])
if (matchedSupportedLanguage) {
return matchedSupportedLanguage
}
}
return SUPPORTED_LANGUAGES.EN
}

export default guessLanguage
37 changes: 37 additions & 0 deletions packages/griffith/src/contexts/Language/guessLanguage.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import guessLanguage from './guessLanguage'
import SUPPORTED_LANGUAGES from './supportedLanguages'

describe('guessLanguage', () => {
it('should return first suppored language in the list', () => {
expect(guessLanguage(['zh-tw', 'en'])).toBe(SUPPORTED_LANGUAGES.ZH_HANT)
expect(guessLanguage(['fr', 'en'])).toBe(SUPPORTED_LANGUAGES.EN)
})

it('should return default language if no match found', () => {
expect(guessLanguage(['es', 'de'])).toBe(SUPPORTED_LANGUAGES.EN)
})

it('should return default language if provided empty list', () => {
expect(guessLanguage([])).toBe(SUPPORTED_LANGUAGES.EN)
})

it('handle various Chinese language codes', () => {
expect(guessLanguage(['zh-CN'])).toBe(SUPPORTED_LANGUAGES.ZH_HANS)
expect(guessLanguage(['zh-SG'])).toBe(SUPPORTED_LANGUAGES.ZH_HANS)

expect(guessLanguage(['zh-TW'])).toBe(SUPPORTED_LANGUAGES.ZH_HANT)
expect(guessLanguage(['zh-HK'])).toBe(SUPPORTED_LANGUAGES.ZH_HANT)

expect(guessLanguage(['zh-cmn-Hans'])).toBe(SUPPORTED_LANGUAGES.ZH_HANS)
expect(guessLanguage(['cmn-Hans-CN'])).toBe(SUPPORTED_LANGUAGES.ZH_HANS)
expect(guessLanguage(['zh-cmn-Hans-HK'])).toBe(SUPPORTED_LANGUAGES.ZH_HANS)

expect(guessLanguage(['zh-cmn-Hant'])).toBe(SUPPORTED_LANGUAGES.ZH_HANT)
expect(guessLanguage(['zh-cmn-Hant'])).toBe(SUPPORTED_LANGUAGES.ZH_HANT)
expect(guessLanguage(['zh-cmn-Hant-CN'])).toBe(SUPPORTED_LANGUAGES.ZH_HANT)
})

it('prefer Simplified Chinese to Traditional if not specified', () => {
expect(guessLanguage(['zh'])).toBe(SUPPORTED_LANGUAGES.ZH_HANS)
})
})
1 change: 1 addition & 0 deletions packages/griffith/src/contexts/Language/index.js
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export {default as LanguageContext} from './LanguageContext'
export {default as LanguageProvider} from './LanguageProvider'
8 changes: 8 additions & 0 deletions packages/griffith/src/contexts/Language/supportedLanguages.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const SUPPORTED_LANGUAGES = {
EN: 'en',
JA: 'hans',
ZH_HANS: 'zh-Hans',
ZH_HANT: 'zh-Hant',
}

export default SUPPORTED_LANGUAGES

0 comments on commit 9ffffc0

Please sign in to comment.