package main import ( "encoding/csv" "fmt" "os" "path/filepath" "strings" ) func setField(all [][]string, header []string, field, col, value string) { colIdx := -1 for i, h := range header { if h == col { colIdx = i break } } if colIdx < 0 { panic(col) } for i := 1; i < len(all); i++ { for len(all[i]) < len(header) { all[i] = append(all[i], "") } if all[i][0] == field { all[i][colIdx] = value return } } panic("missing " + field) } func getField(all [][]string, header []string, field, col string) string { colIdx := -1 for i, h := range header { if h == col { colIdx = i break } } for i := 1; i < len(all); i++ { if len(all[i]) > 0 && all[i][0] == field && colIdx >= 0 && colIdx < len(all[i]) { return all[i][colIdx] } } return "" } func main() { root := `D:\vpn navi` path := filepath.Join(root, "store.csv") f, err := os.Open(path) if err != nil { panic(err) } r := csv.NewReader(f) r.FieldsPerRecord = -1 r.LazyQuotes = true all, err := r.ReadAll() f.Close() if err != nil { panic(err) } header := all[0] // Relative paths for Partner Center: upload folder with store.csv + screen/ ruShots := []string{ "screen/1.ru.png", "screen/2.ru.png", "screen/3.ru.png", "screen/4.ru.png", "screen/5.ru.png", "screen/6.ru.png", "screen/12dark.png", "screen/13dark.png", "screen/14dark.png", "screen/15dark.png", "screen/16dark.png", "screen/9.png", } enShots := []string{ "screen/7.en.png", "screen/8.en.png", "screen/9.png", "screen/10.en.png", "screen/11.en.png", "screen/12dark.png", "screen/13dark.png", "screen/14dark.png", "screen/15dark.png", "screen/16dark.png", } ruCaptions := [][2]string{ {"Главный экран: подключение и статус защиты", "Home: connect and protection status"}, {"Список серверов с флагами и пингом", "Server list with flags and ping"}, {"Настройки: тема, язык, Kill Switch", "Settings: theme, language, Kill Switch"}, {"Статистика использования", "Usage statistics"}, {"Помощь и полезные ссылки", "Help and useful links"}, {"Добавление конфигурации", "Add configuration"}, {"Тёмная тема: главный экран", "Dark theme: home"}, {"Тёмная тема: серверы", "Dark theme: servers"}, {"Тёмная тема: настройки", "Dark theme: settings"}, {"Тёмная тема: статистика", "Dark theme: statistics"}, {"Тёмная тема: помощь", "Dark theme: help"}, {"Общий вид приложения", "App overview"}, } enCaptions := []string{ "Home: connect and protection status", "Server list with flags and ping", "App overview", "Settings: theme, language, Kill Switch", "Statistics and help", "Dark theme: home", "Dark theme: servers", "Dark theme: settings", "Dark theme: statistics", "Dark theme: help", } for i, p := range ruShots { setField(all, header, fmt.Sprintf("DesktopScreenshot%d", i+1), "default", p) } for i, p := range enShots { setField(all, header, fmt.Sprintf("DesktopScreenshot%d", i+1), "en", p) } // Clear en slots beyond enShots so Partner Center falls back to default for RU-only extras for i := len(enShots); i < 30; i++ { setField(all, header, fmt.Sprintf("DesktopScreenshot%d", i+1), "en", "") } // Clear default slots beyond ruShots for i := len(ruShots); i < 30; i++ { setField(all, header, fmt.Sprintf("DesktopScreenshot%d", i+1), "default", "") } for i, c := range ruCaptions { field := fmt.Sprintf("DesktopScreenshotCaption%d", i+1) setField(all, header, field, "default", c[0]) en := c[1] if i < len(enCaptions) { en = enCaptions[i] } setField(all, header, field, "en", en) } for i := len(ruCaptions); i < 30; i++ { field := fmt.Sprintf("DesktopScreenshotCaption%d", i+1) setField(all, header, field, "default", "") setField(all, header, field, "en", "") } out, err := os.Create(path) if err != nil { panic(err) } if _, err := out.Write([]byte{0xEF, 0xBB, 0xBF}); err != nil { panic(err) } w := csv.NewWriter(out) if err := w.WriteAll(all); err != nil { panic(err) } w.Flush() out.Close() for i := 1; i <= 12; i++ { d := getField(all, header, fmt.Sprintf("DesktopScreenshot%d", i), "default") e := getField(all, header, fmt.Sprintf("DesktopScreenshot%d", i), "en") if d == "" && e == "" { continue } fmt.Printf("%d default=%s en=%s\n", i, d, e) for _, p := range []string{d, e} { if p == "" { continue } full := filepath.Join(root, filepath.FromSlash(p)) if _, err := os.Stat(full); err != nil { fmt.Println(" MISSING", full) } } } fmt.Println("updated", path, "rows", len(all)) _ = strings.TrimSpace }