-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: universal environment #832
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -3,11 +3,41 @@ | |||||||||||||||||
* SPDX-License-Identifier: GPL-3.0-or-later | ||||||||||||||||||
*/ | ||||||||||||||||||
|
||||||||||||||||||
declare global { | ||||||||||||||||||
// eslint-disable-next-line camelcase, no-var | ||||||||||||||||||
var _nc_l10n_locale: string | undefined | ||||||||||||||||||
// eslint-disable-next-line camelcase, no-var | ||||||||||||||||||
var _nc_l10n_language: string | undefined | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
/** | ||||||||||||||||||
* Returns the user's locale | ||||||||||||||||||
* @example 'de_DE' | ||||||||||||||||||
*/ | ||||||||||||||||||
export function getLocale(): string { | ||||||||||||||||||
return document.documentElement.dataset.locale || 'en' | ||||||||||||||||||
// Web-browser runtime | ||||||||||||||||||
if (typeof document !== 'undefined' && document.documentElement.dataset.locale) { | ||||||||||||||||||
return document.documentElement.dataset.locale | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
// Node.js runtime | ||||||||||||||||||
if ('_nc_l10n_locale' in globalThis && globalThis._nc_l10n_locale) { | ||||||||||||||||||
return globalThis._nc_l10n_locale | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
// Fallback to English | ||||||||||||||||||
return 'en' | ||||||||||||||||||
Comment on lines
+23
to
+29
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
/** | ||||||||||||||||||
* Set the user's locale | ||||||||||||||||||
* @param locale - The locale to set | ||||||||||||||||||
*/ | ||||||||||||||||||
export function setLocale(locale: string): void { | ||||||||||||||||||
if (typeof document !== 'undefined') { | ||||||||||||||||||
document.documentElement.lang = locale | ||||||||||||||||||
} | ||||||||||||||||||
globalThis._nc_l10n_locale = locale | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
/** | ||||||||||||||||||
|
@@ -20,9 +50,32 @@ export function getCanonicalLocale(): string { | |||||||||||||||||
|
||||||||||||||||||
/** | ||||||||||||||||||
* Returns the user's language | ||||||||||||||||||
* @example 'de-DE' | ||||||||||||||||||
*/ | ||||||||||||||||||
export function getLanguage(): string { | ||||||||||||||||||
return document.documentElement.lang || 'en' | ||||||||||||||||||
// Web-browser runtime | ||||||||||||||||||
if (typeof document !== 'undefined' && document.documentElement.lang) { | ||||||||||||||||||
return document.documentElement.lang | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
// Node.js runtime | ||||||||||||||||||
if ('_nc_l10n_language' in globalThis && globalThis._nc_l10n_language) { | ||||||||||||||||||
return globalThis._nc_l10n_language | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
// Fallback to English | ||||||||||||||||||
return 'en' | ||||||||||||||||||
Comment on lines
+61
to
+67
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here
Suggested change
|
||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
/** | ||||||||||||||||||
* Set the user's language | ||||||||||||||||||
* @param language - The language to set | ||||||||||||||||||
*/ | ||||||||||||||||||
export function setLanguage(language: string): void { | ||||||||||||||||||
if (typeof document !== 'undefined') { | ||||||||||||||||||
document.documentElement.lang = language | ||||||||||||||||||
} | ||||||||||||||||||
globalThis._nc_l10n_language = language | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
/** | ||||||||||||||||||
|
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
@@ -3,14 +3,13 @@ | |||||||||
* SPDX-License-Identifier: GPL-3.0-or-later | ||||||||||
*/ | ||||||||||
import type { Translations } from './registry' | ||||||||||
import { getLanguage, getLocale } from './locale' | ||||||||||
import { getLanguage } from './locale' | ||||||||||
import { | ||||||||||
getAppTranslations, | ||||||||||
hasAppTranslations, | ||||||||||
registerAppTranslations, | ||||||||||
unregisterAppTranslations, | ||||||||||
} from './registry' | ||||||||||
import { generateFilePath } from '@nextcloud/router' | ||||||||||
|
||||||||||
import DOMPurify from 'dompurify' | ||||||||||
import escapeHTML from 'escape-html' | ||||||||||
|
@@ -154,47 +153,29 @@ export function translatePlural( | |||||||||
* the translations are loaded | ||||||||||
* @return {Promise} promise | ||||||||||
*/ | ||||||||||
export function loadTranslations(appName: string, callback: (...args: []) => unknown) { | ||||||||||
interface TranslationBundle { | ||||||||||
translations: Translations | ||||||||||
pluralForm: string | ||||||||||
} | ||||||||||
|
||||||||||
if (hasAppTranslations(appName) || getLocale() === 'en') { | ||||||||||
export async function loadTranslations(appName: string, callback: (...args: []) => unknown) { | ||||||||||
if (hasAppTranslations(appName) || getLanguage() === 'en') { | ||||||||||
return Promise.resolve().then(callback) | ||||||||||
} | ||||||||||
|
||||||||||
const url = generateFilePath(appName, 'l10n', getLocale() + '.json') | ||||||||||
const { generateFilePath } = await import('@nextcloud/router') | ||||||||||
const url = generateFilePath(appName, 'l10n', getLanguage() + '.json') | ||||||||||
|
||||||||||
const promise = new Promise<TranslationBundle>((resolve, reject) => { | ||||||||||
const request = new XMLHttpRequest() | ||||||||||
request.open('GET', url, true) | ||||||||||
request.onerror = () => { | ||||||||||
reject(new Error(request.statusText || 'Network error')) | ||||||||||
} | ||||||||||
request.onload = () => { | ||||||||||
if (request.status >= 200 && request.status < 300) { | ||||||||||
try { | ||||||||||
const bundle = JSON.parse(request.responseText) | ||||||||||
if (typeof bundle.translations === 'object') resolve(bundle) | ||||||||||
} catch (error) { | ||||||||||
// error is probably a SyntaxError due to invalid response text, this is handled by next line | ||||||||||
} | ||||||||||
reject(new Error('Invalid content of translation bundle')) | ||||||||||
} else { | ||||||||||
reject(new Error(request.statusText)) | ||||||||||
} | ||||||||||
const response = await fetch(url) | ||||||||||
if (!response.ok) { | ||||||||||
throw new Error(response.statusText || 'Network error') | ||||||||||
} | ||||||||||
try { | ||||||||||
const bundle = await response.json() | ||||||||||
if (typeof bundle.translations === 'object') { | ||||||||||
register(appName, bundle.translations) | ||||||||||
return Promise.resolve(bundle).then(callback) | ||||||||||
} | ||||||||||
request.send() | ||||||||||
}) | ||||||||||
|
||||||||||
// load JSON translation bundle per AJAX | ||||||||||
return promise | ||||||||||
.then((result) => { | ||||||||||
register(appName, result.translations) | ||||||||||
return result | ||||||||||
}) | ||||||||||
.then(callback) | ||||||||||
throw new Error('Invalid content of translation bundle') | ||||||||||
Comment on lines
+170
to
+174
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I personally prefer error handling instead of success handling if (typeof bundle.translations !== 'object') {
throw new Error('Invalid content of translation bundle')
}
register(appName, bundle.translations)
return callback(bundle) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I only wanted to change |
||||||||||
} catch { | ||||||||||
// Error is probably a SyntaxError due to invalid response, this is handled by the next line | ||||||||||
Comment on lines
+175
to
+176
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will remove useful information for debugging, instead "duplicate here"
Suggested change
|
||||||||||
} | ||||||||||
throw new Error('Invalid content of translation bundle') | ||||||||||
} | ||||||||||
|
||||||||||
/** | ||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will make it available also in exported typings.
Should probably be moved to a
globals.d.ts
file