Merge branch 'i18n' of gitlab.cip.ifi.lmu.de:jost/UniWorX into i18n

This commit is contained in:
Sarah Vaupel 2019-10-30 10:34:29 +01:00
commit d91a13925d
32 changed files with 244 additions and 21 deletions

View File

@ -1,3 +1,5 @@
import moment from 'moment';
/**
* I18n
*
@ -13,10 +15,15 @@
export class I18n {
translations = {};
_translations = {};
_datetimeLocale = undefined;
add(id, translation) {
this.translations[id] = translation;
if (!this._translations[id]) {
this._translations[id] = translation;
} else {
throw new Error('I18N Error: Attempting to set translation multiple times for »' + id + '«!');
}
}
addMany(manyTranslations) {
@ -24,9 +31,27 @@ export class I18n {
}
get(id) {
if (!this.translations[id]) {
if (!this._translations[id]) {
throw new Error('I18N Error: Translation missing for »' + id + '«!');
}
return this.translations[id];
return this._translations[id];
}
setDatetimeLocale(locale) {
if (!this._datetimeLocale) {
moment.locale(locale);
this._datetimeLocale = locale;
} else {
throw new Error('I18N Error: Attempting to set datetime locale multiple times!');
}
}
getDatetimeLocale() {
if (!this._datetimeLocale) {
throw new Error('I18N Error: Attempting to access datetime locale when it has not been set!');
}
return this._datetimeLocale;
}
}

View File

@ -48,9 +48,6 @@ const DATEPICKER_CONFIG = {
timeMinutes: 0,
timeSeconds: 0,
// german settings
// TODO: hardcoded, get from current language / settings
locale: 'de',
weekStart: 1,
dateFormat: FORM_DATE_FORMAT_DATE_DT,
timeFormat: FORM_DATE_FORMAT_TIME_DT,
@ -86,6 +83,7 @@ export class Datepicker {
datepickerInstance;
_element;
elementType;
_locale;
constructor(element) {
if (!element) {
@ -96,6 +94,8 @@ export class Datepicker {
return false;
}
this._locale = window.App.i18n.getDatetimeLocale();
// initialize datepickerCollections singleton if not already done
if (!Datepicker.datepickerCollections) {
Datepicker.datepickerCollections = new Map();
@ -134,7 +134,7 @@ export class Datepicker {
}
// initialize tail.datetime (datepicker) instance and let it do weird stuff with the element value
this.datepickerInstance = datetime(this._element, { ...datepickerGlobalConfig, ...datepickerConfig });
this.datepickerInstance = datetime(this._element, { ...datepickerGlobalConfig, ...datepickerConfig, locale: this._locale });
// reset date to something sane
if (parsedMomentDate)

View File

@ -2104,3 +2104,9 @@ MenuGlossary: Begriffsverzeichnis
Applicant: Bewerber
CourseParticipant: Kursteilnehmer
Administrator: Administrator
CsvFormat: CSV-Format
ExerciseSheet: Übungsblatt
DefinitionCourseEvents: Kurstermine
DefinitionCourseNews: Kurs-Aktuelles
Invitations: Einladungen

View File

@ -1802,7 +1802,7 @@ ApplicationRatingSection: Grading
ApplicationRatingSectionSelfTip: You are authorised to edit the application as well as it's grading.
AllocationSchoolShort: Department
Allocation: Central alloction
Allocation: Central allocation
AllocationRegisterTo: Registration until
AllocationListTitle: Central allocations
@ -2100,3 +2100,9 @@ MenuGlossary: Glossary
Applicant: Applicant
CourseParticipant: Course participant
Administrator: Administrator
CsvFormat: CSV format
ExerciseSheet: Exercise sheet
DefinitionCourseEvents: Course occurrences
DefinitionCourseNews: Course news
Invitations: Invitations

View File

@ -1930,6 +1930,7 @@ siteLayout' headingOverride widget = do
let
-- See Utils.Frontend.I18n and files in messages/frontend for message definitions
frontendI18n = toJSON (mr :: FrontendMessage -> Text)
frontendDatetimeLocale <- toJSON <$> selectLanguage frontendDatetimeLocales
pc <- widgetToPageContent $ do
-- fonts

View File

@ -2,6 +2,7 @@ module Handler.Info where
import Import
import Handler.Utils
import Handler.Info.TH
import qualified Data.Map as Map
import qualified Data.CaseInsensitive as CI
@ -84,7 +85,4 @@ getGlossaryR =
$(widgetFile "glossary")
where
entries = $(i18nWidgetFiles "glossary")
msgMap = Map.fromList
[ ("applicant" , MsgApplicant )
, ("course-participant", MsgCourseParticipant)
]
msgMap = $(glossaryTerms "glossary")

23
src/Handler/Info/TH.hs Normal file
View File

@ -0,0 +1,23 @@
module Handler.Info.TH
( glossaryTerms
) where
import Import
import Handler.Utils.I18n
import Language.Haskell.TH
import qualified Data.Char as Char
import qualified Data.Map.Strict as Map
import qualified Data.Text as Text
glossaryTerms :: FilePath -> Q Exp
glossaryTerms basename = do
translationsAvailable <- i18nWidgetFilesAvailable' basename
let terms = Map.mapWithKey (\k _ -> "Msg" <> unPathPiece k) translationsAvailable
[e|Map.fromList $(listE . map (\(int, msg) -> tupE [litE . stringL $ repack int, conE $ mkName msg]) $ Map.toList terms)|]
where
unPathPiece :: Text -> String
unPathPiece = repack . mconcat . map (over _head Char.toUpper) . Text.splitOn "-"

View File

@ -1,10 +1,13 @@
module Handler.Utils.I18n
where
( i18nWidgetFile
, i18nWidgetFilesAvailable, i18nWidgetFilesAvailable', i18nWidgetFiles
) where
import Import
import Language.Haskell.TH
import Language.Haskell.TH.Syntax (qRunIO)
import qualified Language.Haskell.TH.Syntax as TH
import qualified Data.List as List
import qualified Data.List.NonEmpty as NonEmpty
@ -47,8 +50,8 @@ i18nWidgetFile basename = do
] ++ [ clause [wildP] (normalB [e| error "selectLanguage returned an invalid translation" |]) [] ] -- Fallback mostly there so compiler does not complain about non-exhaustive pattern match
] [e|selectLanguage availableTranslations' >>= $(varE ws)|]
i18nWidgetFiles :: FilePath -> Q Exp
i18nWidgetFiles basename = do
i18nWidgetFilesAvailable' :: FilePath -> Q (Map Text (NonEmpty Text))
i18nWidgetFilesAvailable' basename = do
let i18nDirectory = "templates" </> "i18n" </> basename
availableFiles <- qRunIO $ listDirectory i18nDirectory
let fileKinds' = fmap (pack . dropExtension . takeBaseName &&& toTranslation . pack . takeBaseName) availableFiles
@ -58,6 +61,15 @@ i18nWidgetFiles basename = do
availableTranslations' <- iforM fileKinds $ \kind -> maybe (fail $ "" <> i18nDirectory <> " has no translations for " <> unpack kind <> "") return . NonEmpty.nonEmpty
return availableTranslations'
i18nWidgetFilesAvailable :: FilePath -> Q Exp
i18nWidgetFilesAvailable = TH.lift <=< i18nWidgetFilesAvailable'
i18nWidgetFiles :: FilePath -> Q Exp
i18nWidgetFiles basename = do
availableTranslations' <- i18nWidgetFilesAvailable' basename
-- Dispatch to correct language (depending on user settings via `selectLanguage`) at run time
ws <- newName "ws" -- Name for dispatch function
letE

View File

@ -1,5 +1,6 @@
module Utils.Frontend.I18n
( FrontendMessage(..)
, frontendDatetimeLocales
) where
import ClassyPrelude
@ -14,6 +15,9 @@ import Data.Aeson.Types (toJSONKeyText)
import Data.Aeson.TH
import qualified Data.Char as Char
import Data.List.NonEmpty (NonEmpty(..))
import Text.Shakespeare.I18N (Lang)
-- | I18n-Messages used in JavaScript-Frontend
--
@ -39,3 +43,7 @@ instance ToJSONKey FrontendMessage where
toJSONKey = toJSONKeyText toPathPiece
instance FromJSONKey FrontendMessage where
fromJSONKey = FromJSONKeyTextParser $ parseJSON . String
frontendDatetimeLocales :: NonEmpty Lang
frontendDatetimeLocales = "de" :| ["en"]

View File

@ -11,8 +11,6 @@ import qualified Data.List as List
import qualified Data.CaseInsensitive as CI
import Control.Lens (none)
import Yesod.Core.Types (HandlerData(handlerRequest), YesodRequest(reqLangs))
import qualified Network.Wai.Parse as NWP
@ -41,7 +39,7 @@ selectLanguages avL (l:ls)
, l'' <- matchesFor l'
, langMatches lParts' l''
]
= let now = nonEmpty . filter (\l' -> none (((==) `on` CI.mk) l') ls) $ sortOn (Down . length) found
= let now = nonEmpty $ sortOn (Down . length) found
others = selectLanguages avL ls
in maybe id (\now' others' -> NonEmpty.fromList $ toList now' ++ filter (`notElem` toList now') (toList others')) now others
| otherwise = selectLanguages avL ls

View File

@ -11,4 +11,4 @@
margin-left: 12px
dd + dt, .dd + dt, dd + .dt, .dd + .dt
margin-top: 17px
margin-top: 17px

View File

@ -1,6 +1,6 @@
if (window.App) {
window.App.i18n.addMany(#{frontendI18n});
// window.App.i18n.setLang(lang); TODO: set language string for datepicker config
window.App.i18n.setDatetimeLocale(#{frontendDatetimeLocale});
} else {
throw new Error('I18n JavaScript service is missing!');
}

View File

@ -0,0 +1,7 @@
$newline never
<dd>
Nutzer, die, um die Funktionstüchtigkeit des Systems zu erhalten, über #
erweiterte Rechte innerhalb eines oder mehrerer Institute verfügen.<br />
Haben vollen Zugriff auf alle Kurse und Funktionen innerhalb ihrer Institute #
und auf einige systemweite Funktionalitäten wie z.B. das Ausstellen von #
Uni2work-internen Kennungen.

View File

@ -0,0 +1,7 @@
$newline never
<dd>
Da verfügbare Kapazitäten in einigen Sorten von Veranstaltung (speziell #
Praktika und Seminare) i.A. nicht hinreichend sind für alle Studierenden die #
in einem bestimmten Semester an einer deartigen Veranstaltung teilnehmen #
wollen oder müssen, werden die verfügbaren Plätze zentral auf die #
Interessenten verteilt.

View File

@ -0,0 +1,4 @@
$newline never
<dd>
Nutzer, die von einem Kursverwalter beauftragt wurden bei der Korrektur von #
Übungsblättern und/oder Prüfungen mitzuwirken.

View File

@ -0,0 +1,14 @@
$newline never
<dd>
<p>
Wenn eine Veranstaltung ein Bewerbungsverfahren hat, werden, statt sich als #
Student direkt für die Veranstaltung anzumelden, nur Bewerbungen an die #
Veranstaltung gestellt.<br />
Es ist dann Aufgabe der Kursverwalter die Bewerbungen zu bewerten und ggf. zu #
akzeptieren.
<p>
Auch Veranstaltungen, die an einer Zentralanmeldung teilnehmen, können ein #
Bewerbungsverfahren haben oder nicht.<br />
In diesem Fall werden immer Bewerbungen (über die Zentralanmeldung) an den #
Kurs gestellt, es werden jedoch die Einstellungen vom kurseigenen #
Bewerbungsverfahren übernommen (z.B. ob die Abgabe von Dateien erlaubt ist).

View File

@ -0,0 +1,8 @@
$newline never
<dt .sec>
Anmeldungsvorlagen
<dd>
Wenn eine Veranstaltung ein Bewerbungsverfahren hat, dass die Abgabe von #
Dateien erlaubt, gibt es für Kursverwalter die Möglichkeit einen Satz von #
Dateien zu publizieren der potentiellen Bewerbern dabei helfen soll #
Bewerbungen anzufertigen, die den Erwartungen der Kursverwalter entsprechen.

View File

@ -0,0 +1,4 @@
$newline never
<dd>
Es lassen sich quasi beliebige Prüfungsformen (Projektabnahmen, mündliche #
Prüfungen, Klausuren, ...) in Uni2work modellieren.

View File

@ -0,0 +1,5 @@
$newline never
<dd>
Nutzer die bei der Organisation einer Veranstaltung mitwirken und hierfür vom #
Nutzer, der den Kurs im System angelegt hat, volle Kontrolle über alle Aspekte #
der Veranstaltung erhalten haben.

View File

@ -0,0 +1,5 @@
$newline never
<dd>
Kursverwalter haben die Möglichkeit direkt in Uni2work zusätzliche #
Kursunterlagen (z.B. Foliensätze oder Programmbeispiele) an ihre #
Kursteilnehmer zu verteilen.

View File

@ -0,0 +1,12 @@
$newline never
<dt .sec>
CSV-Datei
<dt .sec>
CSV-Import
<dt .sec>
CSV-Export
<dd>
Ein weit verbreitetes Format zum semi-strukturierten Datenaustausch zwischen #
unterschiedlichen Systemen.<br />
Kann von den meisten gängigen Tabellenkalkulations-Programmen verarbeitet #
werden.

View File

@ -0,0 +1,5 @@
$newline never
<dd>
Kursverwalter haben die Möglichkeit Termine im Bezug auf ihre Veranstaltung #
(Vorlesungen, Zentralübung, Klausureinsicht, ...) direkt auf der Kursseite zu #
publizieren.

View File

@ -0,0 +1,4 @@
$newline never
<dd>
Kursverwalter haben die Möglichkeit Neuigkeiten und Ankündigungen im Bezug auf #
ihre Veranstaltung direkt auf der Kursseite zu publizieren.

View File

@ -0,0 +1,8 @@
$newline never
<dd>
Kursverwalter (und von ihnen beauftragte Korrektoren) können die Ergebnisse #
einer Prüfung direkt in Uni2work hinterlegen.<br />
Dies dient sowohl der Rückmeldung an den jeweiligen Studierenden als auch #
können Prüfungsämter, mit den notwendigen Berechtigungen, die #
Prüfungsleistungen direkt aus Uni2work mit ihren eigenen Verwaltungssystemen #
synchronisieren.

View File

@ -0,0 +1,8 @@
$newline never
<dd>
Kursverwalter haben die Möglichkeit Übungsaufgaben zu ihren Veranstaltung #
direkt in Uni2work an die Kursteilnehmer zu verteilen.<br />
Gewöhnlicherweise haben Kursteilnehmer dann die Möglichkeit ihre erarbeiteten #
Lösungen in Uni2work hochzuladen (oder die Abgabe in einem externen System, #
z.B. auf Papier zu markieren) sodass Korrektor, Feedback und etwaige #
Bonuspunkte ebenfalls direkt in Uni2work verwaltet werden können.

View File

@ -0,0 +1,13 @@
$newline never
<dd>
Es besteht in Uni2work an vielen Stellen die Möglichkeit andere Benutzer in #
einen Prozess mit einzubeziehen (z.B. als Kursverwalter, Korrektor, #
Mitabgebender, ...). #
In solchen Fällen ist die interne Benutzerkennung des gewünschten Benutzers #
(z.B. die Campus Kennung) im Allgemeinen nicht bekannt.<br />
Deswegen gibt es gewöhnlicherweise die Möglichkeit eine Einladung an eine #
beliebige E-Mail Adresse zu verschicken. #
Wird eine derartige Einladung vom Empfänger angenommen (hierbei wird der #
korrekte Nutzer dann anhand des Logins des Empfängers identifiziert) wird der #
Nutzer ohne weiteres Zutun des Senders in den gewünschten Prozess #
miteinbezogen.

View File

@ -0,0 +1,6 @@
$newline never
<dd>
Das System markiert für jeden Nutzer eine gewisse Anzahl von Kursen als von #
besonderem Interesse.<br />
Die derart markierten Kurse werden für gewöhnlich in einer Leiste am linken #
Rand des Browserfensters angezeigt.

View File

@ -0,0 +1,6 @@
$newline never
<dd>
Diese Berechtigung wird einzelnen Benutzern von einem Administrator für ein #
bestimmtes Institut erteilt.<br />
Diese Benutzer können dann die Teilnehmerlisten aller Kurse des relevanten #
Instituts einsehen um z.B. Vorlesungsumfragen durchzuführen.

View File

@ -0,0 +1,11 @@
$newline never
<dd>
<p>
Modelliert jene Stellen der Universität, die Zugriff auf Prüfungsleistungen #
benötigen um sicherzustellen, dass Studienmodalitäten erfüllt und Leistungen #
korrekt anerkannt werden.<br />
<p>
<i>Teil des Prüfungsamts</i> ist eine Berechtigung die einzelnen Benutzern von #
einem Administrator für ein bestimmtes Institut eingeräumt wird.<br />
Diese Benutzer haben dann u.A. Zugriff auf alle beim relevanten Institut #
erbrachten und in Uni2work hinterlegten Prüfungsleistungen.

View File

@ -0,0 +1,4 @@
$newline never
<dd>
Nutzer denen von einem Administrator das Recht eingeräumt wurde innerhalb #
eines Instituts neue Veranstaltungen anzulegen.

View File

@ -0,0 +1,5 @@
$newline never
<dd>
Das System ist in den meisten Aspekten in Institute unterteilt.<br />
Kurse haben stets eine Institutszugehörigkeit und die meisten #
Benutzerberechtigungen werden Institutsweise vergeben.

View File

@ -0,0 +1,10 @@
$newline never
<dd>
Ist die Abgabe für ein Übungsblatt über ein Uni2work-externes System (z.B. auf #
Papier) vorgesehen so können sich Kursteilnehmer auf der Seite des jeweiligen #
Übungsblattes Pseudonyme generieren lassen.<br />
Wenn die externe Abgabe mit einem derartigen Pseudonym markiert wird haben #
Korrektoren später die Möglichkeit Abgaben in Uni2work anzulegen die zu den #
externen Abgaben korrespondieren.<br />
So kann Feedback und etwaige Bonuspunkte direkt in Uni2work verwaltet werden, #
obwohl die tatsächlich Abgabe extern geschehen ist.