| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152 |
- package main
- import (
- "encoding/json"
- "math"
- "net/http"
- "os"
- "path/filepath"
- "sort"
- "strings"
- "imuslab.com/arozos/mod/utils"
- )
- // localeFileSchema is the top-level structure shared by all locale JSON files.
- type localeFileSchema struct {
- Author string `json:"author"`
- Keys map[string]localeKeyEntry `json:"keys"`
- }
- type localeKeyEntry struct {
- Name string `json:"name"`
- }
- // InfoHandleGetLocaleInfo returns locale coverage statistics.
- // It reads every JSON file under ./web/SystemAO/locale/ (one level of sub-dirs),
- // uses file_explorer.json as the canonical language baseline, and reports:
- // - coverage % per language (how many files have that language)
- // - a deduplicated contributors list
- func InfoHandleGetLocaleInfo(w http.ResponseWriter, r *http.Request) {
- type LanguageEntry struct {
- Code string `json:"code"`
- Name string `json:"name"`
- FileCount int `json:"fileCount"`
- TotalFiles int `json:"totalFiles"`
- Coverage float64 `json:"coverage"`
- }
- type Response struct {
- Languages []LanguageEntry `json:"languages"`
- Contributors []string `json:"contributors"`
- TotalFiles int `json:"totalFiles"`
- }
- localeRoot := "./web/SystemAO/locale"
- // ── 1. Collect all JSON file paths (root + one level of sub-dirs) ──────────
- var jsonFiles []string
- entries, err := os.ReadDir(localeRoot)
- if err != nil {
- utils.SendErrorResponse(w, "Failed to read locale directory: "+err.Error())
- return
- }
- for _, e := range entries {
- if e.IsDir() {
- subEntries, err2 := os.ReadDir(filepath.Join(localeRoot, e.Name()))
- if err2 != nil {
- continue
- }
- for _, se := range subEntries {
- if !se.IsDir() && filepath.Ext(se.Name()) == ".json" {
- jsonFiles = append(jsonFiles, filepath.Join(localeRoot, e.Name(), se.Name()))
- }
- }
- } else if filepath.Ext(e.Name()) == ".json" {
- jsonFiles = append(jsonFiles, filepath.Join(localeRoot, e.Name()))
- }
- }
- // ── 2. Parse file_explorer.json to get the baseline language set ────────────
- baseData, err := os.ReadFile(filepath.Join(localeRoot, "file_explorer.json"))
- if err != nil {
- utils.SendErrorResponse(w, "Failed to read file_explorer.json: "+err.Error())
- return
- }
- var base localeFileSchema
- if err = json.Unmarshal(baseData, &base); err != nil {
- utils.SendErrorResponse(w, "Failed to parse file_explorer.json: "+err.Error())
- return
- }
- // Build a map: langCode -> display name (from file_explorer.json)
- langNames := make(map[string]string, len(base.Keys))
- for code, entry := range base.Keys {
- langNames[code] = entry.Name
- }
- // ── 3. Walk every JSON file, tally language presence and collect authors ────
- langFileCounts := make(map[string]int, len(langNames))
- contributorsSet := make(map[string]bool)
- for _, path := range jsonFiles {
- data, err := os.ReadFile(path)
- if err != nil {
- continue
- }
- var lf localeFileSchema
- if err = json.Unmarshal(data, &lf); err != nil {
- continue
- }
- for _, part := range strings.Split(lf.Author, ",") {
- part = strings.TrimSpace(part)
- if part != "" {
- contributorsSet[part] = true
- }
- }
- for code := range lf.Keys {
- if _, isBaseLang := langNames[code]; isBaseLang {
- langFileCounts[code]++
- }
- }
- }
- totalFiles := len(jsonFiles)
- // ── 4. Build sorted language list ──────────────────────────────────────────
- languages := make([]LanguageEntry, 0, len(langNames))
- for code, name := range langNames {
- count := langFileCounts[code]
- coverage := 0.0
- if totalFiles > 0 {
- coverage = math.Round(float64(count)/float64(totalFiles)*1000) / 10
- }
- languages = append(languages, LanguageEntry{
- Code: code,
- Name: name,
- FileCount: count,
- TotalFiles: totalFiles,
- Coverage: coverage,
- })
- }
- sort.Slice(languages, func(i, j int) bool {
- if languages[i].Coverage != languages[j].Coverage {
- return languages[i].Coverage > languages[j].Coverage
- }
- return languages[i].Code < languages[j].Code
- })
- // ── 5. Build sorted contributors list ──────────────────────────────────────
- contributors := make([]string, 0, len(contributorsSet))
- for c := range contributorsSet {
- contributors = append(contributors, c)
- }
- sort.Strings(contributors)
- resp := Response{
- Languages: languages,
- Contributors: contributors,
- TotalFiles: totalFiles,
- }
- js, _ := json.Marshal(resp)
- utils.SendJSONResponse(w, string(js))
- }
|