1 | import {IncomingMessage, ServerResponse} from "http";
|
2 | import * as UrlParser from 'url';
|
3 |
|
4 | const SUB_DIR = /^(\/(\w\w(_\w\w)?))(?:\/|$)/;
|
5 | const SUB_DOMAIN_PIPE_REGEX = /(?:^|_)(\w\w(?:_\w\w)?)_(?:b\-[mt]\-)?[0-9a-f]{24,25}_pipe/i;
|
6 | const SUB_DOMAIN_REGEX = /^(?:www\.)?(\w\w(?:_\w\w)?)\./i;
|
7 |
|
8 | export interface ExtendedRequest extends IncomingMessage {
|
9 | originalUrl?: string;
|
10 | bablic?:{
|
11 | locale: string;
|
12 | proxied?: boolean;
|
13 | }
|
14 | }
|
15 |
|
16 | export interface ExtendedResponse extends ServerResponse {
|
17 | locals?: any;
|
18 | }
|
19 |
|
20 | export type Middleware = (req: IncomingMessage, res: ServerResponse, next: () => void) => void;
|
21 |
|
22 | export interface KeywordMapper {
|
23 | [locale: string]:{
|
24 | [keyword:string]: string
|
25 | }
|
26 | }
|
27 |
|
28 | function getLocaleFromFolder(folderLocale, locales) {
|
29 | var index = locales.indexOf(folderLocale);
|
30 | if (index > -1)
|
31 | return locales[index];
|
32 | folderLocale = folderLocale.substr(0, 2);
|
33 | for (var i = 0; i < locales.length; i++) {
|
34 | if (locales[i].substr(0, 2) == folderLocale)
|
35 | return locales[i];
|
36 | }
|
37 | return '';
|
38 | }
|
39 |
|
40 |
|
41 | export function getLocaleByURL(parsedUrl, locale_detection, localeConfigs, cookieLocale, siteDefaultLocale, detectedLocale, isProxy, explicitLocale, subDirBase, folders, locales) {
|
42 | switch (locale_detection) {
|
43 | case 'querystring':
|
44 | if (parsedUrl.query && typeof(parsedUrl.query) == 'object')
|
45 | return parsedUrl.query.locale;
|
46 | var matches = /locale=([^&]+)/.exec(parsedUrl.query || '');
|
47 | if (matches && matches.length == 2 && matches[1])
|
48 | return matches[1];
|
49 | return cookieLocale || detectedLocale || siteDefaultLocale;
|
50 | case "subdomain":
|
51 | var regex = isProxy ? SUB_DOMAIN_PIPE_REGEX : SUB_DOMAIN_REGEX;
|
52 | var matches = regex.exec(parsedUrl.hostname);
|
53 | if (matches && matches.length > 1 && matches[1])
|
54 | return matches[1];
|
55 | return siteDefaultLocale;
|
56 | case "subdir":
|
57 | var pathname = parsedUrl.pathname;
|
58 | if (subDirBase)
|
59 | pathname = pathname.replace(subDirBase, '');
|
60 | var match = SUB_DIR.exec(pathname);
|
61 | if (match) {
|
62 | if (folders && locales && folders[match[2]])
|
63 | return getLocaleFromFolder(folders[match[2]], locales) || siteDefaultLocale;
|
64 | return match[2];
|
65 | }
|
66 | if (explicitLocale)
|
67 | return explicitLocale;
|
68 | if (cookieLocale)
|
69 | return cookieLocale;
|
70 | return detectedLocale || siteDefaultLocale;
|
71 | case "tld":
|
72 | var matches = /\.(\w\w)$/.exec(parsedUrl.hostname);
|
73 | if (matches && matches.length > 1 && matches[1])
|
74 | return matches[1];
|
75 | return null;
|
76 | case "custom":
|
77 | var parseDomainRule = function (str) {
|
78 | return RegExp((str + '').replace(/([.?+^$[\]\\(){}|-])/g, "\\$1").replace(/\*/g, '.*'), 'i');
|
79 | };
|
80 |
|
81 | for (var locale in localeConfigs) {
|
82 | var urlPattern = localeConfigs[locale];
|
83 | if (urlPattern && parseDomainRule(urlPattern).test(parsedUrl.href))
|
84 | return locale;
|
85 | }
|
86 | return explicitLocale || siteDefaultLocale;
|
87 | case "hash":
|
88 | var matches = /^#!locale=(\w\w(?:_\w\w)?)$/.exec(parsedUrl.hash || '');
|
89 | if (matches && matches.length > 1 && matches[1])
|
90 | return matches[1];
|
91 | return cookieLocale || detectedLocale || siteDefaultLocale;
|
92 | default:
|
93 | return cookieLocale;
|
94 | }
|
95 | }
|
96 | export interface SiteMeta{
|
97 | localeDetection: string;
|
98 | original: string;
|
99 | customUrls: {
|
100 | [locale:string]:string
|
101 | };
|
102 | default: string;
|
103 | autoDetect: boolean;
|
104 | localeKeys: string[];
|
105 | timestamp: number;
|
106 | includeQueryString: boolean;
|
107 | includeHash: boolean;
|
108 | singlePageApp: boolean;
|
109 | qsParams: string[],
|
110 | domain: string;
|
111 | mountSubs: string[];
|
112 | }
|
113 |
|
114 | export interface BablicLinkOptions {
|
115 | subDir?: boolean;
|
116 | subDirBase?: string;
|
117 | subDirOptional?: boolean;
|
118 | returnFull?: boolean;
|
119 | folders?:{[locale:string]:string}
|
120 | }
|
121 |
|
122 | export function getLink(locale: string, parsed: UrlParser.Url, meta: SiteMeta, options?: BablicLinkOptions) {
|
123 | options = options || {};
|
124 | let protocol = parsed.protocol || '';
|
125 | let hostname = parsed.hostname;
|
126 | let pathname = parsed.pathname || '/';
|
127 | let search = parsed.search || '';
|
128 | let hash = parsed.hash || '';
|
129 |
|
130 | let returnFull = options.returnFull;
|
131 | let localeDetection = meta.localeDetection;
|
132 | let original = meta.original;
|
133 | if(options.subDir)
|
134 | localeDetection = 'subdir';
|
135 | if(localeDetection == 'custom' && !(meta.customUrls && meta.customUrls[locale]))
|
136 | localeDetection = 'querystring';
|
137 |
|
138 | switch(localeDetection){
|
139 | case 'custom':
|
140 | let customUrl = meta.customUrls[locale];
|
141 | let confDomain = customUrl.indexOf('/') > -1 ? customUrl.substr(0,customUrl.indexOf('/')) : customUrl;
|
142 | return protocol + '//' + confDomain + pathname + search + hash;
|
143 |
|
144 | case 'querystring':
|
145 | if (/[?&]locale=([^&]+)/.test(search))
|
146 | search = search.replace(/([?&]locale=)([^&]+)/, '$1' + locale);
|
147 | else {
|
148 | if (search)
|
149 | search = search + '&locale=' + locale;
|
150 | else
|
151 | search = '?locale=' + locale;
|
152 | }
|
153 | if(returnFull)
|
154 | return protocol + '//' + hostname + pathname + search + hash;
|
155 |
|
156 | return pathname + search + hash;
|
157 |
|
158 | case 'subdir':
|
159 | if(options.subDirBase)
|
160 | pathname = pathname.replace(options.subDirBase,'');
|
161 | let match = SUB_DIR.exec(pathname);
|
162 | if (match) {
|
163 | pathname = pathname.substr(match[1].length);
|
164 | if (pathname.length == 0)
|
165 | pathname = '/';
|
166 | }
|
167 | let prefix = '';
|
168 | if(options.folders)
|
169 | prefix = '/' + getFolder(locale,options.folders);
|
170 | else if(locale != original)
|
171 | prefix = '/' + locale;
|
172 | if(options.subDirBase && (!options.subDirOptional || locale != original))
|
173 | prefix = options.subDirBase + prefix;
|
174 | if(returnFull)
|
175 | return protocol + '//' + hostname + prefix + pathname + search + hash;
|
176 | return prefix + pathname + search + hash;
|
177 | case 'hash':
|
178 | if(returnFull)
|
179 | return protocol + '//' + hostname + pathname + search + '#locale=' + locale;
|
180 | return '#locale_' + locale;
|
181 | }
|
182 | return `javascript:bablic.setLanguage("${locale}");`;
|
183 | }
|
184 |
|
185 |
|
186 | function getFolder(locale: string,folders:{[locale:string]:string}) :string{
|
187 | for(let folder in folders){
|
188 | if(folders[folder] == locale)
|
189 | return folder;
|
190 | }
|
191 | locale = locale.substr(0,2);
|
192 | for(let folder in folders){
|
193 | if(folders[folder].substr(0,2) == locale)
|
194 | return folder;
|
195 | }
|
196 | return locale;
|
197 | }
|