Skip to content

Commit 76a906b

Browse files
author
Simon Planinschek
committed
Add new Internationalization class in index file
1 parent 4be01a2 commit 76a906b

1 file changed

Lines changed: 158 additions & 3 deletions

File tree

src/index.ts

Lines changed: 158 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,159 @@
1-
import ClientInternationalization from './ClientInternationalization'
2-
import ServerInternationalization from './ServerInternationalization'
1+
import { IncomingMessage } from 'http'
2+
import {
3+
getCookieFromDocument,
4+
canUseDOM,
5+
setCookie,
6+
getCookieFromRequest,
7+
} from './utilities'
38

4-
export { ClientInternationalization, ServerInternationalization }
9+
class Internationalization<T extends string> {
10+
private readonly cookieName: string
11+
12+
supportedLanguages: Array<T>
13+
fallbackLanguage: T
14+
15+
/**
16+
* ClientInternationalization utility package for working with languages
17+
*
18+
* @param supportedLanguages { Array<string> } - List of all supported languages
19+
* @param fallbackLanguage { string } - Fallback language if no language matches
20+
* @param cookieName { string } - Optional: Set a preferred cookie name
21+
*/
22+
constructor(
23+
supportedLanguages: Array<T>,
24+
fallbackLanguage: T,
25+
cookieName?: string
26+
) {
27+
this.supportedLanguages = supportedLanguages
28+
this.fallbackLanguage = fallbackLanguage
29+
30+
this.cookieName = typeof cookieName === 'string' ? cookieName : 'language'
31+
}
32+
33+
/**
34+
* Detect the browser language of the client
35+
* If no language was found or if none of the
36+
* supported language matches a fallback language will be returned
37+
*
38+
* @return {string} - Detected language
39+
*/
40+
detectBrowserLanguage(): T {
41+
// Check if the DOM is presented.
42+
// If the DOM isn't accessible the website may be rendered on a server
43+
if (canUseDOM()) {
44+
// Get browser language
45+
const browserLanguage =
46+
(navigator.languages && navigator.languages[0]) || navigator.language
47+
48+
return (
49+
this.supportedLanguages.find((lang) => lang === browserLanguage) ||
50+
this.fallbackLanguage
51+
)
52+
}
53+
54+
// Return fallback language if no DOM was found
55+
return this.fallbackLanguage
56+
}
57+
58+
/**
59+
* Save a language to a cookie
60+
* If the set language isn't in the list of supported languages
61+
* the fallback language will be returned
62+
*
63+
* @param language { string } - Language to set
64+
*/
65+
setLanguage(language: string): void {
66+
if (canUseDOM()) {
67+
const cookieLanguage =
68+
this.supportedLanguages.find((lang) => lang === language) ||
69+
this.fallbackLanguage
70+
71+
setCookie(this.cookieName, cookieLanguage)
72+
}
73+
}
74+
75+
/**
76+
* Save a language to a cookie
77+
* This method will not check if the language you want to set is supported
78+
* Please note! If you have changed the cookie name, you must change it here as well
79+
*
80+
* @param language { string } - Language to set
81+
* @param cookieName { string } - Optional: Cookie name
82+
*/
83+
static setLanguage(language: string, cookieName?: string): void {
84+
if (canUseDOM()) {
85+
cookieName = typeof cookieName === 'string' ? cookieName : 'language'
86+
87+
setCookie(cookieName, language)
88+
}
89+
}
90+
91+
/**
92+
* Get the current language
93+
* This method will first check if a language cookie is present.
94+
* If no cookie was found the method will get the language form the browser
95+
*
96+
* For handling cookies on the server side pass the request object
97+
*
98+
* @param request { IncomingMessage } - Optional: Request object for accessing cookies over request headers
99+
* @return { string } - Found language or fallback language
100+
*/
101+
detectLanguage(request?: IncomingMessage): T {
102+
// Check if request is not undefined
103+
if (request) {
104+
// Try to get language form cookie
105+
const cookieFromRequest = getCookieFromRequest(this.cookieName, request)
106+
107+
if (cookieFromRequest) {
108+
return cookieFromRequest as T
109+
}
110+
111+
// Get accept language from request header
112+
const acceptLanguage = request.headers['accept-language']
113+
114+
if (acceptLanguage) {
115+
// Extract the locale string and the priority from header string
116+
const requestedLocales = acceptLanguage.split(',').map((part) => {
117+
const [locale, priority] = part.trim().split(';q=')
118+
119+
return { locale, priority: parseInt(priority) }
120+
})
121+
122+
// Get the potential locale from requested locales array
123+
const potentialLocale = requestedLocales
124+
.sort((a, b) => b.priority - a.priority)
125+
.find(
126+
({ locale }) =>
127+
locale !== '*' &&
128+
this.supportedLanguages.some((lang) => locale === lang)
129+
)
130+
131+
// Check if the potential locale is not undefined else return the fallback language
132+
return (potentialLocale
133+
? potentialLocale.locale
134+
: this.fallbackLanguage) as T
135+
}
136+
}
137+
138+
// Check for DOM
139+
if (canUseDOM()) {
140+
// Try to get language form cookie
141+
const language = getCookieFromDocument(this.cookieName)
142+
143+
// If cookie is undefined get the language form the browser
144+
if (language == undefined) {
145+
return this.detectBrowserLanguage()
146+
}
147+
148+
// Return found language or fallback language
149+
return (
150+
this.supportedLanguages.find((lang) => lang === language) ||
151+
this.fallbackLanguage
152+
)
153+
}
154+
155+
return this.fallbackLanguage
156+
}
157+
}
158+
159+
export default Internationalization

0 commit comments

Comments
 (0)