Skip to content

Commit

Permalink
Provide all translation related frontend methods
Browse files Browse the repository at this point in the history
* This provides all functions previously available within
  the `OC.L10N` namespace
* Including translation regestry functions and translation bundle
  loading
* Restructured the source files for better comprehensibility

Signed-off-by: Ferdinand Thiessen <rpm@fthiessen.de>
  • Loading branch information
susnux committed Jan 5, 2023
1 parent f4182fa commit 6d66daf
Show file tree
Hide file tree
Showing 6 changed files with 653 additions and 219 deletions.
121 changes: 121 additions & 0 deletions lib/date.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/// <reference types="@nextcloud/typings" />

declare var window: Nextcloud.v24.WindowWithGlobals

/**
* Get the first day of the week
*
* @return {number}
*/
export function getFirstDay(): number {
if (typeof window.firstDay === 'undefined') {
console.warn('No firstDay found')
return 1
}

return window.firstDay
}

/**
* Get a list of day names (full names)
*
* @return {string[]}
*/
export function getDayNames(): string[] {
if (typeof window.dayNames === 'undefined') {
console.warn('No dayNames found')
return [
'Sunday',
'Monday',
'Tuesday',
'Wednesday',
'Thursday',
'Friday',
'Saturday',
]
}

return window.dayNames
}

/**
* Get a list of day names (short names)
*
* @return {string[]}
*/
export function getDayNamesShort(): string[] {
if (typeof window.dayNamesShort === 'undefined') {
console.warn('No dayNamesShort found')
return ['Sun.', 'Mon.', 'Tue.', 'Wed.', 'Thu.', 'Fri.', 'Sat.']
}

return window.dayNamesShort
}

/**
* Get a list of day names (minified names)
*
* @return {string[]}
*/
export function getDayNamesMin(): string[] {
if (typeof window.dayNamesMin === 'undefined') {
console.warn('No dayNamesMin found')
return ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa']
}

return window.dayNamesMin
}

/**
* Get a list of month names (full names)
*
* @return {string[]}
*/
export function getMonthNames(): string[] {
if (typeof window.monthNames === 'undefined') {
console.warn('No monthNames found')
return [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December',
]
}

return window.monthNames
}

/**
* Get a list of month names (short names)
*
* @return {string[]}
*/
export function getMonthNamesShort(): string[] {
if (typeof window.monthNamesShort === 'undefined') {
console.warn('No monthNamesShort found')
return [
'Jan.',
'Feb.',
'Mar.',
'Apr.',
'May.',
'Jun.',
'Jul.',
'Aug.',
'Sep.',
'Oct.',
'Nov.',
'Dec.',
]
}

return window.monthNamesShort
}
203 changes: 2 additions & 201 deletions lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,201 +1,2 @@
/// <reference types="@nextcloud/typings" />

declare var window: Nextcloud.v16.WindowWithGlobals
| Nextcloud.v17.WindowWithGlobals
| Nextcloud.v18.WindowWithGlobals
| Nextcloud.v19.WindowWithGlobals;

import DOMPurify from 'dompurify'
import escapeHTML from 'escape-html'
import { getAppTranslations } from './registry'

/**
* Returns the user's locale
*/
export function getLocale(): string {
return document.documentElement.dataset.locale || 'en'
}

export function getCanonicalLocale(): string {
return getLocale().replace(/_/g, '-')
}

/**
* Returns the user's language
*/
export function getLanguage(): string {
return document.documentElement.lang || 'en'
}

interface TranslationOptions {
/** enable/disable auto escape of placeholders (by default enabled) */
escape?: boolean,
/** enable/disable sanitization (by default enabled) */
sanitize?: boolean,
}

/**
* Translate a string
*
* @param {string} app the id of the app for which to translate the string
* @param {string} text the string to translate
* @param {object} vars map of placeholder key to value
* @param {number} number to replace %n with
* @param {object} [options] options object
* @return {string}
*/
export function translate(app: string, text: string, vars?: Record<string, any>, number?: number, options?: TranslationOptions): string {
const defaultOptions = {
escape: true,
sanitize: true,
}
const allOptions = Object.assign({}, defaultOptions, options || {})

const identity = (value) => value
const optSanitize = allOptions.sanitize ? DOMPurify.sanitize : identity
const optEscape = allOptions.escape ? escapeHTML : identity

// TODO: cache this function to avoid inline recreation
// of the same function over and over again in case
// translate() is used in a loop
const _build = (text: string, vars?: Record<string, any>, number?: number) => {
return text
.replace(/%n/g, '' + number)
.replace(/{([^{}]*)}/g, (match, key) => {
if (vars === undefined || !(key in vars)) return optSanitize(match)

const r = vars[key]
if (typeof r === 'string' || typeof r === 'number') {
return optSanitize(optEscape(r))
} else {
return optSanitize(match)
}
}
)
}

const bundle = getAppTranslations(app)
const translation = bundle.translations[text] || text

if (typeof vars === 'object' || number !== undefined) {
return optSanitize(_build(translation, vars, number))
} else {
return optSanitize(translation)
}
}

/**
* Translate a plural string
*
* @param {string} app the id of the app for which to translate the string
* @param {string} textSingular the string to translate for exactly one object
* @param {string} textPlural the string to translate for n objects
* @param {number} number number to determine whether to use singular or plural
* @param {Object} vars of placeholder key to value
* @param {object} options options object
* @return {string}
*/

export function translatePlural(app: string, textSingular: string, textPlural: string, number: number, vars?: object, options?: TranslationOptions): string {
const identifier = '_' + textSingular + '_::_' + textPlural + '_'
const bundle = getAppTranslations(app)
const value = bundle.translations[identifier]

if (typeof (value) !== 'undefined') {
const translation = value
if (Array.isArray(translation)) {
const plural = bundle.pluralFunction(number)
return translate(app, translation[plural], vars, number, options)
}
}

if (number === 1) {
return translate(app, textSingular, vars, number, options)
} else {
return translate(app, textPlural, vars, number, options)
}
}

/**
* Get the first day of the week
*
* @return {number}
*/
export function getFirstDay(): number {
if (typeof window.firstDay === 'undefined') {
console.warn('No firstDay found')
return 1
}

return window.firstDay
}

/**
* Get a list of day names (full names)
*
* @return {string[]}
*/
export function getDayNames(): string[] {
if (typeof window.dayNames === 'undefined') {
console.warn('No dayNames found')
return ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']
}

return window.dayNames
}

/**
* Get a list of day names (short names)
*
* @return {string[]}
*/
export function getDayNamesShort(): string[] {
if (typeof window.dayNamesShort === 'undefined') {
console.warn('No dayNamesShort found')
return ['Sun.', 'Mon.', 'Tue.', 'Wed.', 'Thu.', 'Fri.', 'Sat.']
}

return window.dayNamesShort
}

/**
* Get a list of day names (minified names)
*
* @return {string[]}
*/
export function getDayNamesMin(): string[] {
if (typeof window.dayNamesMin === 'undefined') {
console.warn('No dayNamesMin found')
return ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa']
}

return window.dayNamesMin
}

/**
* Get a list of month names (full names)
*
* @return {string[]}
*/
export function getMonthNames(): string[] {
if (typeof window.monthNames === 'undefined') {
console.warn('No monthNames found')
return ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
}

return window.monthNames
}

/**
* Get a list of month names (short names)
*
* @return {string[]}
*/
export function getMonthNamesShort(): string[] {
if (typeof window.monthNamesShort === 'undefined') {
console.warn('No monthNamesShort found')
return ['Jan.', 'Feb.', 'Mar.', 'Apr.', 'May.', 'Jun.', 'Jul.', 'Aug.', 'Sep.', 'Oct.', 'Nov.', 'Dec.']
}

return window.monthNamesShort
}
export * from './translation'
export * from './date'
Loading

0 comments on commit 6d66daf

Please sign in to comment.