i18n.go (17728B)
1 package i18n 2 3 import ( 4 "cerca/util" 5 "fmt" 6 "html/template" 7 "log" 8 "strings" 9 ) 10 11 const toolURL = "https://github.com/cblgh/cerca/releases/tag/pwtool-v1" 12 13 var English = map[string]string{ 14 "About": "about", 15 "Login": "login", 16 "Logout": "logout", 17 "Sort": "sort", 18 "Enter": "enter", 19 "Register": "register", 20 "Bottom": "bottom", 21 22 "LoggedIn": "logged in", 23 "NotLoggedIn": "Not logged in", 24 "LogIn": "log in", 25 "GoBack": "Go back", 26 27 "SortRecentPosts": "recent posts", 28 "SortRecentThreads": "most recent threads", 29 30 "modlogResetPassword": `<code>{{ .Data.Time }}</code> <b>{{ .Data.ActingUsername }}</b> reset a user's password`, 31 "modlogResetPasswordAdmin": `<code>{{ .Data.Time }}</code> <b>{{ .Data.ActingUsername }}</b> reset <b> {{ .Data.RecipientUsername}}</b>'s password`, 32 "modlogRemoveUser": `<code>{{ .Data.Time }}</code> <b>{{ .Data.ActingUsername }}</b> removed a user's account`, 33 "modlogMakeAdmin": `<code>{{ .Data.Time }}</code> <b>{{ .Data.ActingUsername }}</b> made <b> {{ .Data.RecipientUsername}}</b> an admin`, 34 "modlogAddUser": `<code>{{ .Data.Time }}</code> <b>{{ .Data.ActingUsername }}</b> manually registered an account for a new user`, 35 "modlogAddUserAdmin": `<code>{{ .Data.Time }}</code> <b>{{ .Data.ActingUsername }}</b> manually registered an account for <b> {{ .Data.RecipientUsername }}</b>`, 36 "modlogDemoteAdmin": `<code>{{ .Data.Time }}</code> <b>{{ .Data.ActingUsername }}</b> demoted <b> 37 {{ if eq .Data.ActingUsername .Data.RecipientUsername }} themselves 38 {{ else }} {{ .Data.RecipientUsername}} {{ end }}</b> from admin back to normal user`, 39 "modlogXProposedY": `<code>{{ .Data.Time }}</code> <b>{{ .Data.ActingUsername }}</b> proposed: {{ .Data.Action }}`, 40 "modlogProposalMakeAdmin": `Make <b> {{ .Data.RecipientUsername}}</b> admin`, 41 "modlogProposalDemoteAdmin": `Demote <b> {{ .Data.RecipientUsername}}</b> from role admin`, 42 "modlogProposalRemoveUser": `Remove user <b> {{ .Data.RecipientUsername }} </b>`, 43 "modlogConfirm": "{{ .Data.Action }} <i>confirmed by {{ .Data.ActingUsername }}</i>", 44 "modlogVeto": "<s>{{ .Data.Action }}</s> <i>vetoed by {{ .Data.ActingUsername }}</i>", 45 46 "Admins": "admins", 47 "AdminVeto": "Veto", 48 "AdminConfirm": "Confirm", 49 "AdminForumAdministration": "Forum Administration", 50 "AdminYou": "you!", 51 "AdminUsers": "Users", 52 "AdminNoAdmins": "There are no admins", 53 "AdminNoUsers": "There are no other users", 54 "AdminNoPendingProposals": "There are no pending proposals", 55 "AdminAddNewUser": "Add new user", 56 "AdminAddNewUserQuestion": "Does someone wish attendence? You can ", 57 "AdminStepDown": "Step down", 58 "AdminStepDownExplanation": "If you want to stop being an admin, you can", 59 "AdminViewPastActions": "View past actions in the", 60 "ModerationLog": "moderation log", 61 "AdminDemote": "Demote", 62 "DeletedUser": "deleted user", 63 "RemoveAccount": "remove account", 64 "AdminMakeAdmin": "Make admin", 65 "Submit": "Submit", 66 "AdminSelfConfirmationsHover": "a week must pass before self-confirmations are ok", 67 "Proposal": "Proposal", 68 "PendingProposals": "Pending Proposals", 69 "AdminSelfProposalsBecomeValid": "Date self-proposals become valid", 70 "AdminPendingExplanation": `Two admins are required for <i>making a user an admin</i>, <i>demoting an existing 71 admin</i>, or <i>removing a user</i>. The first proposes the action, the second confirms 72 (or vetos) it. If enough time elapses without a veto, the proposer may confirm their own 73 proposal.`, 74 75 "AdminAddUserExplanation": "Register a new user account. After registering the account you will be given a generated password and instructions to pass onto the user.", 76 "AdminForumHasAdmins": "The forum currently has the following admins", 77 "AdminOnlyLoggedInMayView": "Only logged in users may view the forum's admins.", 78 "AdminPasswordSuccessInstructions": `Instructions: %s's password was set to: %s. After logging in, please change your password by going to /reset`, 79 80 "ModLogNoActions": "there are no logged moderation actions", 81 "ModLogExplanation": `This resource lists the moderation actions taken by the forum's administrators.`, 82 "ModLogExplanationAdmin": `You are viewing this page as an admin, you will see slightly more details.`, 83 "ModLogOnlyLoggedInMayView": "Only logged in users may view the moderation log.", 84 85 "LoginNoAccount": "Don't have an account yet? <a href='/register'>Register</a> one.", 86 "LoginFailure": "<b>Failed login attempt:</b> incorrect password, wrong username, or a non-existent user.", 87 "LoginAlreadyLoggedIn": `You are already logged in. Would you like to <a href="/logout">log out</a>?`, 88 89 "Username": "username", 90 "Current": "current", 91 "New": "new", 92 "ChangePasswordDescription": "Use this page to change your password.", 93 "Password": "password", 94 "PasswordMin": "Must be at least 9 characters long", 95 "PasswordForgot": "Forgot your password?", 96 97 "Threads": "threads", 98 "ThreadNew": "new thread", 99 "ThreadThe": "the thread", 100 "Index": "index", 101 "GoBackToTheThread": "Go back to the thread", 102 103 "ThreadCreate": "Create thread", 104 "Title": "Title", 105 "Content": "Content", 106 "Private": "Private", 107 "Create": "Create", 108 "TextareaPlaceholder": "Tabula rasa", 109 110 "PasswordReset": "reset password", 111 "PasswordResetSuccess": "Reset password—success!", 112 "PasswordResetSuccessMessage": "You reset your password!", 113 "PasswordResetSuccessLinkMessage": "Give it a try and", 114 115 "RegisterMessage": "You already have an account (you are logged in with it).", 116 "RegisterLinkMessage": "Visit the", 117 "RegisterSuccess": "registered successfully", 118 119 "ErrUnaccepted": "Unaccepted request", 120 "ErrGeneric401": "Unauthorized", 121 "ErrGeneric401Message": "You do not have permissions to perform this action.", 122 "ErrEdit404": "Post not found", 123 "ErrEdit404Message": "This post cannot be found for editing", 124 "ErrThread404": "Thread not found", 125 "ErrThread404Message": "The thread does not exist (anymore?)", 126 "ErrGeneric404": "Page not found", 127 "ErrGeneric404Message": "The visited page does not exist (anymore?). Error code %d.", 128 129 "NewThreadMessage": "Only members of this forum may create new threads", 130 "NewThreadLinkMessage": "If you are a member,", 131 "NewThreadCreateError": "Error creating thread", 132 "NewThreadCreateErrorMessage": "There was a database error when creating the thread, apologies.", 133 "PostEdit": "Post preview", 134 "PostPrivate": "This is a private thread, only logged-in users can see it and read its posts.", 135 136 "AriaPostMeta": "Post meta", 137 "AriaDeletePost": "Delete this post", 138 "AriaRespondIntoThread": "Respond into this thread", 139 "PromptDeleteQuestion": "Delete post for all posterity?", 140 "Delete": "delete", 141 "Edit": "edit", 142 "EditedAt": "edited at", 143 "Post": "post", 144 "Save": "Save", 145 "Author": "Author", 146 "Responded": "responded", 147 "YourAnswer": "Your answer", 148 149 "AriaHome": "Home", 150 "ThreadStartNew": "Start a new thread", 151 152 "RegisterHTMLMessage": `You now have an account! Welcome. Visit the <a href="/">index</a> to read and reply to threads, or start a new one.`, 153 154 "RegisterVerificationCode": "Your verification code is", 155 "RegisterVerificationInstructionsTitle": "Verification instructions", 156 "RegisterVerificationLink": "Verification link", 157 "RegisterConductCodeBoxOne": `I have refreshed my memory of the <a target="_blank" href="{{ .Data.Link }}">{{ .Data.Name }} Code of Conduct</a>`, 158 "RegisterConductCodeBoxTwo": `Yes, I have actually <a target="_blank" href="{{ .Data.Link }}">read it</a>`, 159 160 "NewPassword": "new password", 161 "ChangePassword": "change password", 162 } 163 164 var Swedish = map[string]string{ 165 "About": "om", 166 "Login": "logga in", 167 "Logout": "logga ut", 168 "Sort": "sortera", 169 "Enter": "skicka", 170 "Register": "registrera", 171 "Bottom": "hoppa ner", 172 173 "LoggedIn": "inloggad", 174 "NotLoggedIn": "Ej inloggad", 175 "LogIn": "logga in", 176 "GoBack": "Go back", 177 178 "SortRecentPosts": "nyast poster", 179 "SortRecentThreads": "nyast trådar", 180 181 "LoginNoAccount": "Saknar du konto? <a href='/register'>Skapa</a> ett.", 182 "LoginFailure": "<b>Misslyckat inloggningsförsök:</b> inkorrekt lösenord, fel användernamn, eller obefintlig användare.", 183 "LoginAlreadyLoggedIn": `Du är redan inloggad. Vill du <a href="/logout">logga ut</a>?`, 184 185 "Username": "användarnamn", 186 "Current": "nuvarande", 187 "New": "nytt", 188 "ChangePasswordDescription": "På den här sidan kan du ändra ditt lösenord.", 189 "Password": "lösenord", 190 "PasswordMin": "Måste vara minst 9 karaktärer långt", 191 "PasswordForgot": "Glömt lösenordet?", 192 193 "Threads": "trådar", 194 "ThreadNew": "ny tråd", 195 "ThreadThe": "tråden", 196 "Index": "index", 197 "GoBackToTheThread": "Go back to the thread", 198 199 "ThreadCreate": "Skapa en tråd", 200 "Title": "Titel", 201 "Content": "Innehåll", 202 "Create": "Skapa", 203 "TextareaPlaceholder": "Tabula rasa", 204 205 "PasswordReset": "nollställ lösenord", 206 "PasswordResetSuccess": "Nollställning av lösenord—lyckades!", 207 "PasswordResetSuccessMessage": "Du har nollställt ditt lösenord!", 208 "PasswordResetSuccessLinkMessage": "Ge det ett försök och", 209 210 "RegisterMessage": "Du har redan ett konto (du är inloggad med det).", 211 "RegisterLinkMessage": "Besök", 212 "RegisterSuccess": "konto skapat", 213 214 "ErrUnaccepted": "Ej accepterat request", 215 "ErrThread404": "Tråd ej funnen", 216 "ErrThread404Message": "Denna tråden finns ej (längre?)", 217 "ErrGeneric404": "Sida ej funnen", 218 "ErrGeneric404Message": "Den besökta sidan finns ej (längre?). Felkod %d.", 219 220 "NewThreadMessage": "Enbart medlemmarna av detta forum får skapa nya trådar", 221 "NewThreadLinkMessage": "Om du är en medlem,", 222 "NewThreadCreateError": "Fel uppstod vid trådskapning", 223 "NewThreadCreateErrorMessage": "Det uppstod ett databasfel under trådskapningen, ursäkta.", 224 "PostEdit": "Post preview", 225 226 "AriaPostMeta": "Post meta", 227 "AriaDeletePost": "Delete this post", 228 "AriaRespondIntoThread": "Respond into this thread", 229 "PromptDeleteQuestion": "Radera post för alltid?", 230 "Delete": "radera", 231 "Edit": "redigera", 232 "EditedAt": "redigerat", 233 "Post": "post", 234 "Author": "Författare", 235 "Responded": "svarade", 236 "YourAnswer": "Ditt svar", 237 238 "AriaHome": "Hem", 239 "ThreadStartNew": "Starta ny tråd", 240 241 "RegisterHTMLMessage": `Du har nu ett konto! Välkommen. Besök <a href="/">trådindexet</a> för att läsa och svara på trådar, eller för att starta en ny.`, 242 243 "RegisterVerificationCode": "Din verifikationskod är", 244 "RegisterVerificationInstructionsTitle": "Verification instructions", 245 "RegisterVerificationLink": "Verificationsnyckel", 246 "RegisterConductCodeBoxOne": `I have refreshed my memory of the <a target="_blank" href="{{ .Data.Link }}">{{ .Data.Name }} Code of Conduct</a>`, 247 "RegisterConductCodeBoxTwo": `Yes, I have actually <a target="_blank" href="{{ .Data.Link }}">read it</a>`, 248 249 "PasswordResetDescription": "På denna sida går vi igenom ett par steg för att säkert nollställa ditt lösenord—utan att behöva ta till mejl!", 250 "PasswordResetUsernameQuestion": "För de första: hur löd användarnamnet?", 251 "NewPassword": "nytt lösenord", 252 "ChangePassword": "ändra lösenord", 253 } 254 255 var EspanolMexicano = map[string]string{ 256 "About": "acerca de", 257 "Login": "loguearse", 258 "Logout": "logout", 259 "Sort": "sort", 260 "Register": "register", 261 "Enter": "entrar", 262 "Bottom": "bottom", 263 264 "LoggedIn": "logged in", 265 "NotLoggedIn": "Not logged in", 266 "LogIn": "log in", 267 "GoBack": "Go back", 268 269 "SortRecentPosts": "recent posts", 270 "SortRecentThreads": "most recent threads", 271 272 "LoginNoAccount": "¿No tienes una cuenta? <a href='/register'>Registra</a> una. ", 273 "LoginFailure": "<b>Failed login attempt:</b> incorrect password, wrong username, or a non-existent user.", 274 "LoginAlreadyLoggedIn": `You are already logged in. Would you like to <a href="/logout">log out</a>?`, 275 276 "Username": "usuarie", 277 "Current": "current", 278 "New": "new", 279 "ChangePasswordDescription": "Use this page to change your password.", 280 "Password": "contraseña", 281 "PasswordMin": "Debe tener por lo menos 9 caracteres.", 282 "PasswordForgot": "Olvidaste tu contraseña?", 283 284 "Threads": "threads", 285 "ThreadNew": "new thread", 286 "ThreadThe": "the thread", 287 "Index": "index", 288 "GoBackToTheThread": "Go back to the thread", 289 290 "ThreadCreate": "Create thread", 291 "Title": "Title", 292 "Content": "Content", 293 "Create": "Create", 294 "TextareaPlaceholder": "Tabula rasa", 295 296 "PasswordReset": "reset password", 297 "PasswordResetSuccess": "Reset password—success!", 298 "PasswordResetSuccessMessage": "You reset your password!", 299 "PasswordResetSuccessLinkMessage": "Give it a try and", 300 301 "RegisterMessage": "You already have an account (you are logged in with it).", 302 "RegisterLinkMessage": "Visit the", 303 "RegisterSuccess": "registered successfully", 304 305 "ErrUnaccepted": "Unaccepted request", 306 "ErrThread404": "Thread not found", 307 "ErrThread404Message": "The thread does not exist (anymore?)", 308 "ErrGeneric404": "Page not found", 309 "ErrGeneric404Message": "The visited page does not exist (anymore?). Error code %d.", 310 311 "NewThreadMessage": "Only members of this forum may create new threads", 312 "NewThreadLinkMessage": "If you are a member,", 313 "NewThreadCreateError": "Error creating thread", 314 "NewThreadCreateErrorMessage": "There was a database error when creating the thread, apologies.", 315 "PostEdit": "Post preview", 316 "ThreadStartNew": "Start a new thread", 317 318 "AriaPostMeta": "Post meta", 319 "AriaDeletePost": "Delete this post", 320 "AriaRespondIntoThread": "Respond into this thread", 321 "AriaHome": "Home", 322 "PromptDeleteQuestion": "Delete post for all posterity?", 323 "Delete": "delete", 324 "Edit": "editar", 325 "EditedAt": "editado a las", 326 "Post": "post", 327 "Save": "Save", 328 "Author": "Author", 329 "Responded": "responded", 330 "YourAnswer": "Your answer", 331 332 "RegisterHTMLMessage": `You now have an account! Welcome. Visit the <a href="/">index</a> to read and reply to threads, or start a new one.`, 333 334 "RegisterVerificationCode": "Your verification code is", 335 "RegisterVerificationInstructionsTitle": "Verification instructions", 336 "RegisterVerificationLink": "Verification link", 337 "RegisterConductCodeBoxOne": `I have refreshed my memory of the <a target="_blank" href="{{ .Data.Link }}">{{ .Data.Name }} Code of Conduct</a>`, 338 "RegisterConductCodeBoxTwo": `Yes, I have actually <a target="_blank" href="{{ .Data.Link }}">read it</a>`, 339 340 "PasswordResetDescription": "On this page we'll go through a few steps to securely reset your password—without resorting to any emails!", 341 "PasswordResetUsernameQuestion": "First up: what was your username?", 342 "NewPassword": "new password", 343 "ChangePassword": "change password", 344 } 345 346 var translations = map[string]map[string]string{ 347 "English": English, 348 "EspañolMexicano": EspanolMexicano, 349 "Swedish": Swedish, 350 } 351 352 type TranslationData struct { 353 Data interface{} 354 } 355 356 func (tr *Translator) TranslateWithData(key string, data TranslationData) string { 357 phrase := translations[tr.Language][key] 358 t, err := template.New(key).Parse(phrase) 359 ed := util.Describe("i18n translation") 360 ed.Check(err, "parse translation phrase") 361 sb := new(strings.Builder) 362 err = t.Execute(sb, data) 363 ed.Check(err, "execute template with data") 364 return sb.String() 365 } 366 367 func (tr *Translator) Translate(key string) string { 368 var empty TranslationData 369 return tr.TranslateWithData(key, empty) 370 } 371 372 type Translator struct { 373 Language string 374 } 375 376 func Init(lang string) Translator { 377 if _, ok := translations[lang]; !ok { 378 log.Fatalln(fmt.Sprintf("language '%s' is not translated yet", lang)) 379 } 380 return Translator{lang} 381 } 382 383 // usage: 384 // tr := Init("EnglishSwedish") 385 // fmt.Println(tr.Translate("LoginNoAccount")) 386 // fmt.Println(tr.TranslateWithData("LoginDescription", Community{"Merveilles", "https://merveill.es"}))