mirror of
https://github.com/AdguardTeam/AdGuardHome.git
synced 2025-12-20 01:11:03 +08:00
update download script
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import React, { useState } from 'react';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
|
||||
import { Trans, useTranslation } from 'react-i18next';
|
||||
|
||||
@@ -43,7 +43,7 @@ export const Form = ({
|
||||
onSubmit,
|
||||
}: FormProps) => {
|
||||
const { t, i18n } = useTranslation();
|
||||
React.useEffect(() => {
|
||||
useEffect(() => {
|
||||
preloadServicesLocale(i18n.language).catch(() => {});
|
||||
}, [i18n.language]);
|
||||
const {
|
||||
|
||||
@@ -22,19 +22,15 @@ import (
|
||||
"github.com/AdguardTeam/golibs/syncutil"
|
||||
)
|
||||
|
||||
const (
|
||||
hostlistRegistryProjectID = "hostlists-registry"
|
||||
jsonMessageKey = "message"
|
||||
jsonIndentPrefix = ""
|
||||
jsonIndentString = " "
|
||||
)
|
||||
|
||||
// download and save all translations.
|
||||
func (c *twoskyClient) download(ctx context.Context, l *slog.Logger) (err error) {
|
||||
return c.downloadTo(ctx, l, localesDir, defaultBaseFile)
|
||||
}
|
||||
|
||||
// downloadTo downloads and saves all translations to the specified outputDir
|
||||
// using the specified baseFile name.
|
||||
func (c *twoskyClient) downloadTo(
|
||||
ctx context.Context,
|
||||
l *slog.Logger,
|
||||
outputDir string,
|
||||
baseFile string,
|
||||
) (err error) {
|
||||
var numWorker int
|
||||
|
||||
flagSet := flag.NewFlagSet("download", flag.ExitOnError)
|
||||
@@ -53,6 +49,29 @@ func (c *twoskyClient) downloadTo(
|
||||
usage("count must be positive")
|
||||
}
|
||||
|
||||
// download locales from AdGuard Home crowdin project
|
||||
if err = c.downloadTo(ctx, l, localesDir, defaultBaseFile, numWorker); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// download services from AdGuard Hostlist Registry crowdin project
|
||||
c.projectID = hostlistRegistryProjectID
|
||||
if err = c.downloadTo(ctx, l, servicesLocalesDir, servicesBaseFile, numWorker); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// downloads and saves all translations to the specified outputDir
|
||||
// using the specified baseFile name.
|
||||
func (c *twoskyClient) downloadTo(
|
||||
ctx context.Context,
|
||||
l *slog.Logger,
|
||||
outputDir string,
|
||||
baseFile string,
|
||||
numWorker int,
|
||||
) (err error) {
|
||||
downloadURI := c.uri.JoinPath("download")
|
||||
|
||||
wg := &sync.WaitGroup{}
|
||||
@@ -70,11 +89,6 @@ func (c *twoskyClient) downloadTo(
|
||||
baseFile: baseFile,
|
||||
}
|
||||
|
||||
// Ensure output directory exists.
|
||||
if err = os.MkdirAll(outputDir, 0o775); err != nil {
|
||||
return fmt.Errorf("creating output dir: %w", err)
|
||||
}
|
||||
|
||||
for range numWorker {
|
||||
wg.Go(dw.run)
|
||||
}
|
||||
@@ -93,40 +107,65 @@ func (c *twoskyClient) downloadTo(
|
||||
return nil
|
||||
}
|
||||
|
||||
func normalizeServicesJSON(data []byte) []byte {
|
||||
if b, err := unwrapMessageJSON(data); err == nil {
|
||||
data = b
|
||||
}
|
||||
if b, err := indentJSON(data); err == nil {
|
||||
data = b
|
||||
}
|
||||
return data
|
||||
// extracts the "message" values into a flat map and returns the result
|
||||
// formatted with consistent JSON indentation
|
||||
func normalizeServicesJSON(data []byte) ([]byte, error) {
|
||||
unwrapped, err := extractMessagesJSON(data)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("normalize services json: extraction failed: %w", err)
|
||||
}
|
||||
|
||||
func unwrapMessageJSON(data []byte) ([]byte, error) {
|
||||
var wrapped map[string]struct {
|
||||
Message string `json:"message"`
|
||||
}
|
||||
if err := json.Unmarshal(data, &wrapped); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
flat := make(map[string]string, len(wrapped))
|
||||
for k, v := range wrapped {
|
||||
flat[k] = v.Message
|
||||
}
|
||||
return json.Marshal(flat)
|
||||
indented, err := indentJSON(unwrapped)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("normalize services json: indentation failed: %w", err)
|
||||
}
|
||||
|
||||
func indentJSON(data []byte) ([]byte, error) {
|
||||
var buf bytes.Buffer
|
||||
if err := json.Indent(&buf, data, "", " "); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
return indented, nil
|
||||
}
|
||||
|
||||
// converts a wrapped services JSON of shape
|
||||
// {"key": {"message": "..."}} into a flat {"key": "..."}
|
||||
func extractMessagesJSON(input []byte) ([]byte, error) {
|
||||
var wrapped map[string]map[string]any
|
||||
if err := json.Unmarshal(input, &wrapped); err != nil {
|
||||
return nil, fmt.Errorf("extract json: unmarshal wrapped payload: %w", err)
|
||||
}
|
||||
|
||||
flattened := make(map[string]string, len(wrapped))
|
||||
for key, inner := range wrapped {
|
||||
rawValue, ok := inner[jsonMessageKey]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("extract json: missing %q field for key %q", jsonMessageKey, key)
|
||||
}
|
||||
|
||||
message, ok := rawValue.(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("extract json: %q field for key %q is not a string", jsonMessageKey, key)
|
||||
}
|
||||
|
||||
flattened[key] = message
|
||||
}
|
||||
|
||||
result, err := json.Marshal(flattened)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("extract json: marshal flattened map: %w", err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// formats JSON using the configured prefix and indent
|
||||
func indentJSON(data []byte) (b []byte, err error) {
|
||||
var buffer bytes.Buffer
|
||||
|
||||
err = json.Indent(&buffer, data, jsonIndentPrefix, jsonIndentString)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("indent json: formatting failed: %w", err)
|
||||
}
|
||||
|
||||
return buffer.Bytes(), nil
|
||||
}
|
||||
|
||||
// printFailedLocales prints sorted list of failed downloads, if any. l and
|
||||
// failed must not be nil.
|
||||
func printFailedLocales(
|
||||
ctx context.Context,
|
||||
l *slog.Logger,
|
||||
@@ -191,7 +230,10 @@ func saveToFile(
|
||||
}
|
||||
|
||||
if baseFile == servicesBaseFile {
|
||||
data = normalizeServicesJSON(data)
|
||||
data, err = normalizeServicesJSON(data)
|
||||
if err != nil {
|
||||
return fmt.Errorf("normalize services JSON for %q: %w", code, err)
|
||||
}
|
||||
}
|
||||
|
||||
name := filepath.Join(outputDir, code+".json")
|
||||
|
||||
@@ -90,11 +90,6 @@ func main() {
|
||||
cli = errors.Must(conf.toClient())
|
||||
|
||||
errors.Check(cli.download(ctx, l))
|
||||
case "download-services":
|
||||
cli = errors.Must(conf.toClient())
|
||||
|
||||
cli.projectID = "hostlists-registry"
|
||||
errors.Check(cli.downloadTo(ctx, l, servicesLocalesDir, servicesBaseFile))
|
||||
case "unused":
|
||||
err := unused(ctx, l, conf.LocalizableFiles[0])
|
||||
errors.Check(err)
|
||||
@@ -120,10 +115,7 @@ Commands:
|
||||
summary
|
||||
Print summary.
|
||||
download [-n <count>]
|
||||
Download translations. count is a number of concurrent downloads.
|
||||
download-services [-n <count>]
|
||||
Download services translations from 'hostlists-registry' project into
|
||||
client/src/__locales-services.
|
||||
Download translations (both app and services). count is a number of concurrent downloads.
|
||||
unused
|
||||
Print unused strings.
|
||||
upload
|
||||
|
||||
Reference in New Issue
Block a user