forked from thomiceli/opengist
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add translation system (thomiceli#104)
- Loading branch information
Showing
27 changed files
with
774 additions
and
205 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
package i18n | ||
|
||
import ( | ||
"fmt" | ||
"github.com/thomiceli/opengist/internal/i18n/locales" | ||
"golang.org/x/text/cases" | ||
"golang.org/x/text/language" | ||
"golang.org/x/text/language/display" | ||
"gopkg.in/yaml.v3" | ||
"html/template" | ||
"io" | ||
"io/fs" | ||
"path/filepath" | ||
"strings" | ||
) | ||
|
||
var title = cases.Title(language.English) | ||
var Locales = NewLocaleStore() | ||
|
||
type LocaleStore struct { | ||
Locales map[string]*Locale | ||
} | ||
|
||
type Locale struct { | ||
Code string | ||
Name string | ||
Messages map[string]string | ||
} | ||
|
||
// NewLocaleStore creates a new LocaleStore | ||
func NewLocaleStore() *LocaleStore { | ||
return &LocaleStore{ | ||
Locales: make(map[string]*Locale), | ||
} | ||
} | ||
|
||
// loadLocaleFromYAML loads a single Locale from a given YAML file | ||
func (store *LocaleStore) loadLocaleFromYAML(localeCode, path string) error { | ||
a, err := locales.Files.Open(path) | ||
if err != nil { | ||
return err | ||
} | ||
data, err := io.ReadAll(a) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
tag, err := language.Parse(localeCode) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
name := display.Self.Name(tag) | ||
if tag == language.AmericanEnglish { | ||
name = "English" | ||
} | ||
|
||
locale := &Locale{ | ||
Code: localeCode, | ||
Name: title.String(name), | ||
Messages: make(map[string]string), | ||
} | ||
|
||
err = yaml.Unmarshal(data, &locale.Messages) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
store.Locales[localeCode] = locale | ||
return nil | ||
} | ||
|
||
func (store *LocaleStore) LoadAll() error { | ||
return fs.WalkDir(locales.Files, ".", func(path string, d fs.DirEntry, err error) error { | ||
if err != nil { | ||
return err | ||
} | ||
if !d.IsDir() { | ||
localeKey := strings.TrimSuffix(path, filepath.Ext(path)) | ||
err := store.loadLocaleFromYAML(localeKey, path) | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
return nil | ||
}) | ||
} | ||
|
||
func (store *LocaleStore) GetLocale(lang string) (*Locale, error) { | ||
_, ok := store.Locales[lang] | ||
if !ok { | ||
return nil, fmt.Errorf("locale %s not found", lang) | ||
} | ||
|
||
return store.Locales[lang], nil | ||
} | ||
|
||
func (store *LocaleStore) HasLocale(lang string) bool { | ||
_, ok := store.Locales[lang] | ||
return ok | ||
} | ||
|
||
func (store *LocaleStore) MatchTag(langs []language.Tag) string { | ||
for _, lang := range langs { | ||
if store.HasLocale(lang.String()) { | ||
return lang.String() | ||
} | ||
} | ||
|
||
return "en-US" | ||
} | ||
|
||
func (l *Locale) Tr(key string, args ...any) template.HTML { | ||
message := l.Messages[key] | ||
|
||
if message == "" { | ||
return Locales.Locales["en-US"].Tr(key, args...) | ||
} | ||
|
||
if len(args) == 0 { | ||
return template.HTML(message) | ||
} | ||
|
||
return template.HTML(fmt.Sprintf(message, args...)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,177 @@ | ||
gist.public: Public | ||
gist.unlisted: Unlisted | ||
gist.private: Private | ||
|
||
gist.header.like: Like | ||
gist.header.unlike: Unlike | ||
gist.header.fork: Fork | ||
gist.header.edit: Edit | ||
gist.header.delete: Delete | ||
gist.header.forked-from: Forked from | ||
gist.header.last-active: Last active | ||
gist.header.select-tab: Select a tab | ||
gist.header.code: Code | ||
gist.header.revisions: Revisions | ||
gist.header.revision: Revision | ||
gist.header.clone-http: Clone via %s | ||
gist.header.clone-http-help: Clone with Git using HTTP basic authentication. | ||
gist.header.clone-ssh: Clone via SSH | ||
gist.header.clone-ssh-help: Clone with Git using an SSH key. | ||
gist.header.share: Share | ||
gist.header.share-help: Copy shareable link for this gist. | ||
gist.header.download-zip: Download ZIP | ||
|
||
gist.raw: Raw | ||
gist.file-truncated: This file has been truncated. | ||
gist.watch-full-file: View the full file. | ||
gist.file-not-valid: This file is not a valid CSV file. | ||
gist.no-content: No content | ||
|
||
gist.new.new_gist: New gist | ||
gist.new.title: Title | ||
gist.new.description: Description | ||
gist.new.filename-with-extension: Filename with extension | ||
gist.new.indent-mode: Indent mode | ||
gist.new.indent-mode-space: Space | ||
gist.new.indent-mode-tab: Tab | ||
gist.new.indent-size: Indent size | ||
gist.new.wrap-mode: Wrap mode | ||
gist.new.wrap-mode-no: No wrap | ||
gist.new.wrap-mode-soft: Soft wrap | ||
gist.new.add-file: Add file | ||
gist.new.create-public-button: Create public gist | ||
gist.new.create-unlisted-button: Create unlisted gist | ||
gist.new.create-private-button: Create private gist | ||
|
||
gist.edit.editing: Editing | ||
gist.edit.change-visibility: Make | ||
gist.edit.delete: Delete | ||
gist.edit.cancel: Cancel | ||
gist.edit.save: Save | ||
|
||
gist.list.joined: Joined | ||
gist.list.all: All gists | ||
gist.list.search-results: Search results | ||
gist.list.sort: Sort | ||
gist.list.sort-by-created: created | ||
gist.list.sort-by-updated: updated | ||
gist.list.order-by-asc: Least recently | ||
gist.list.order-by-desc: Recently | ||
gist.list.select-tab: Select a tab | ||
gist.list.liked: Liked | ||
gist.list.likes: likes | ||
gist.list.forked: Forked | ||
gist.list.forked-from: Forked from | ||
gist.list.forks: forks | ||
gist.list.files: files | ||
gist.list.last-active: Last active | ||
gist.list.no-gists: No gists | ||
|
||
gist.forks: Forks | ||
gist.forks.view: View fork | ||
gist.forks.no: No public forks | ||
|
||
gist.likes: Likes | ||
gist.likes.no: No likes yet | ||
|
||
gist.revisions: Revisions | ||
gist.revision.revised: revised this gist | ||
gist.revision.go-to-revision: Go to revision | ||
gist.revision.file-created: file created | ||
gist.revision.file-deleted: file deleted | ||
gist.revision.file-renamed: renamed to | ||
gist.revision.diff-truncated: Diff truncated because it's too large to be shown | ||
gist.revision.file-renamed-no-changes: File renamed without changes | ||
gist.revision.empty-file: Empty file | ||
gist.revision.no-changes: No changes | ||
gist.revision.no-revisions: No revisions to show | ||
|
||
settings: Settings | ||
settings.email: Email | ||
settings.email-help: Used for commits and Gravatar | ||
settings.email-set: Set email | ||
settings.link-accounts: Link accounts | ||
settings.link-github-account: Link GitHub account | ||
settings.link-gitea-account: Link Gitea account | ||
settings.unlink-github-account: Unlink GitHub account | ||
settings.unlink-gitea-account: Unlink Gitea account | ||
settings.delete-account: Delete account | ||
settings.delete-account-confirm: Are you sure you want to delete your account ? | ||
settings.add-ssh-key: Add SSH key | ||
settings.add-ssh-key-help: Used only to pull/push gists using Git via SSH | ||
settings.add-ssh-key-title: Title | ||
settings.add-ssh-key-content: Key | ||
settings.delete-ssh-key: Delete | ||
settings.delete-ssh-key-confirm: Confirm deletion of SSH key | ||
settings.ssh-key-added-at: Added | ||
settings.ssh-key-never-used: Never used | ||
settings.ssh-key-last-used: Last used | ||
|
||
auth.signup-disabled: Administrator has disabled signing up | ||
auth.login: Login | ||
auth.signup: Register | ||
auth.new-account: New account | ||
auth.username: Username | ||
auth.password: Password | ||
auth.register-instead: Register instead | ||
auth.login-instead: Login instead | ||
auth.github-oauth: Continue with GitHub account | ||
auth.gitea-oauth: Continue with Gitea account | ||
|
||
error: Error | ||
|
||
header.menu.all: All | ||
header.menu.new: New | ||
header.menu.search: Search | ||
header.menu.my-gists: My gists | ||
header.menu.liked: Liked | ||
header.menu.admin: Admin | ||
header.menu.settings: Settings | ||
header.menu.logout: Logout | ||
header.menu.register: Register | ||
header.menu.login: Login | ||
header.menu.light: Light | ||
header.menu.dark: Dark | ||
header.menu.system: System | ||
footer.powered-by: Powered by %s | ||
|
||
pagination.older: Older | ||
pagination.newer: Newer | ||
pagination.previous: Previous | ||
pagination.next: Next | ||
|
||
admin.admin_panel: Admin panel | ||
admin.general: General | ||
admin.users: Users | ||
admin.gists: Gists | ||
admin.configuration: Configuration | ||
admin.versions: Versions | ||
admin.ssh_keys: SSH keys | ||
admin.stats: Stats | ||
admin.actions: Actions | ||
admin.actions.sync-fs: Synchronize gists from filesystem | ||
admin.actions.sync-db: Synchronize gists from database | ||
admin.actions.git-gc: Garbage collect git repositories | ||
admin.id: ID | ||
admin.user: User | ||
admin.delete: Delete | ||
admin.created_at: Created | ||
|
||
admin.config-link: This configuration can be %s by a YAML config file and/or environment variables. | ||
admin.config-link-overriden: overridden | ||
admin.disable-signup: Disable signup | ||
admin.disable-signup_help: Forbid the creation of new accounts. | ||
admin.require-login: Require login | ||
admin.require-login_help: Enforce users to be logged in to see gists. | ||
admin.disable-login: Disable login form | ||
admin.disable-login_help: Forbid logging in via the login form to force using OAuth providers instead. | ||
admin.disable-gravatar: Disable Gravatar | ||
admin.disable-gravatar_help: Disable the usage of Gravatar as an avatar provider. | ||
|
||
admin.users.delete_confirm: Do you want to delete this user ? | ||
|
||
admin.gists.title: Title | ||
admin.gists.private: Private ? | ||
admin.gists.nb-files: Nb. files | ||
admin.gists.nb-likes: Nb. likes | ||
admin.gists.delete_confirm: Do you want to delete this gist ? |
Oops, something went wrong.