Merge branch 'i18n' of gitlab.cip.ifi.lmu.de:jost/UniWorX into i18n
This commit is contained in:
commit
d91a13925d
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -2104,3 +2104,9 @@ MenuGlossary: Begriffsverzeichnis
|
||||
|
||||
Applicant: Bewerber
|
||||
CourseParticipant: Kursteilnehmer
|
||||
Administrator: Administrator
|
||||
CsvFormat: CSV-Format
|
||||
ExerciseSheet: Übungsblatt
|
||||
DefinitionCourseEvents: Kurstermine
|
||||
DefinitionCourseNews: Kurs-Aktuelles
|
||||
Invitations: Einladungen
|
||||
@ -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
|
||||
@ -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
|
||||
|
||||
@ -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
23
src/Handler/Info/TH.hs
Normal 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 "-"
|
||||
@ -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
|
||||
|
||||
@ -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"]
|
||||
|
||||
@ -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
|
||||
|
||||
@ -11,4 +11,4 @@
|
||||
margin-left: 12px
|
||||
|
||||
dd + dt, .dd + dt, dd + .dt, .dd + .dt
|
||||
margin-top: 17px
|
||||
margin-top: 17px
|
||||
|
||||
@ -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!');
|
||||
}
|
||||
|
||||
@ -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.
|
||||
7
templates/i18n/glossary/allocation.de-de-formal.hamlet
Normal file
7
templates/i18n/glossary/allocation.de-de-formal.hamlet
Normal 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.
|
||||
4
templates/i18n/glossary/corrector.de-de-formal.hamlet
Normal file
4
templates/i18n/glossary/corrector.de-de-formal.hamlet
Normal 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.
|
||||
@ -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).
|
||||
@ -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.
|
||||
4
templates/i18n/glossary/course-exams.de-de-formal.hamlet
Normal file
4
templates/i18n/glossary/course-exams.de-de-formal.hamlet
Normal file
@ -0,0 +1,4 @@
|
||||
$newline never
|
||||
<dd>
|
||||
Es lassen sich quasi beliebige Prüfungsformen (Projektabnahmen, mündliche #
|
||||
Prüfungen, Klausuren, ...) in Uni2work modellieren.
|
||||
@ -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.
|
||||
@ -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.
|
||||
12
templates/i18n/glossary/csv-format.de-de-formal.hamlet
Normal file
12
templates/i18n/glossary/csv-format.de-de-formal.hamlet
Normal 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.
|
||||
@ -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.
|
||||
@ -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.
|
||||
8
templates/i18n/glossary/exam-result.de-de-formal.hamlet
Normal file
8
templates/i18n/glossary/exam-result.de-de-formal.hamlet
Normal 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.
|
||||
@ -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.
|
||||
13
templates/i18n/glossary/invitations.de-de-formal.hamlet
Normal file
13
templates/i18n/glossary/invitations.de-de-formal.hamlet
Normal 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.
|
||||
@ -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.
|
||||
@ -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.
|
||||
@ -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.
|
||||
@ -0,0 +1,4 @@
|
||||
$newline never
|
||||
<dd>
|
||||
Nutzer denen von einem Administrator das Recht eingeräumt wurde innerhalb #
|
||||
eines Instituts neue Veranstaltungen anzulegen.
|
||||
5
templates/i18n/glossary/school.de-de-formal.hamlet
Normal file
5
templates/i18n/glossary/school.de-de-formal.hamlet
Normal 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.
|
||||
10
templates/i18n/glossary/sheet-pseudonym.de-de-formal.hamlet
Normal file
10
templates/i18n/glossary/sheet-pseudonym.de-de-formal.hamlet
Normal 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.
|
||||
Loading…
Reference in New Issue
Block a user