Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
signalapp
GitHub Repository: signalapp/Signal-iOS
Path: blob/main/Scripts/translation-tool/src/MetadataFile.swift
1 views
//
// Copyright 2022 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//

import Foundation

// Maps Smartling language codes to App Store Connect language codes.
private let languageMap: [String: [String]] = [
    // These languages are returned from Smartling and need to be moved to their correct final destination.
    "ar": ["ar-SA"],
    "ca": ["ca"],
    "cs": ["cs"],
    "da": ["da"],
    "de": ["de-DE"],
    "el": ["el"],
    "es": ["es-ES", "es-MX"],
    "fi": ["fi"],
    "fr": ["fr-CA", "fr-FR"],
    "he": ["he"],
    "hi-IN": ["hi"],
    "hr-HR": ["hr"],
    "hu": ["hu"],
    "id": ["id"],
    "it": ["it"],
    "ja": ["ja"],
    "ko": ["ko"],
    "ms": ["ms"],
    "nb": ["no"],
    "nl": ["nl-NL"],
    "pl": ["pl"],
    "pt-BR": ["pt-BR"],
    "pt-PT": ["pt-PT"],
    "ro-RO": ["ro"],
    "ru": ["ru"],
    "sk-SK": ["sk"],
    "sv": ["sv"],
    "th": ["th"],
    "tr": ["tr"],
    "uk-UA": ["uk"],
    "vi": ["vi"],
    "zh-CN": ["zh-Hans"],
    "zh-HK": ["zh-Hant"],

    // These don't exist in App Store Connect, so there's no need to fetch them from Smartling.
    // "be-BY": [],
    // "bg-BG": [],
    // "bn-BD": [],
    // "fa-IR": [],
    // "ga-IE": [],
    // "gu-IN": [],
    // "lt-LT": [],
    // "mr-IN": [],
    // "sr-YR": [],
    // "ug": [],
    // "ur": [],
    // "yue": [],
    // "zh-TW": [],
]

private let extraEnglishLanguages: [String] = ["en-AU", "en-CA", "en-GB"]

struct MetadataFile: TranslatableFile {
    var filename: String

    var relativeSourcePath: String { relativePath(for: "en-US") }

    private static let relativeDirectoryPath = "fastlane/metadata"

    private func relativePath(for languageCode: String) -> String {
        return "\(Self.relativeDirectoryPath)/\(languageCode)/\(filename)"
    }

    func downloadAllTranslations(to repositoryURL: URL, using client: Smartling) async throws {
        try await withLimitedThrowingTaskGroup(limit: Constant.concurrentRequestLimit) { taskGroup in
            try await taskGroup.addTask {
                // English is special. Instead of downloading a file, we copy the file we
                // uploaded to other English languages.
                let fileURL = repositoryURL.appendingPathComponent(relativeSourcePath)
                try processDownloadedFile(at: fileURL, repositoryURL: repositoryURL, localIdentifiers: extraEnglishLanguages)
            }
            for (remoteIdentifier, localIdentifiers) in languageMap {
                try await taskGroup.addTask {
                    let fileURL = try await client.downloadTranslatedFile(for: filename, in: remoteIdentifier)
                    try processDownloadedFile(at: fileURL, repositoryURL: repositoryURL, localIdentifiers: localIdentifiers)
                }
            }
        }
    }

    private func processDownloadedFile(at fileURL: URL, repositoryURL: URL, localIdentifiers: [String]) throws {
        for localIdentifier in localIdentifiers {
            let localRelativePath = relativePath(for: localIdentifier)
            try FileManager.default.copyItem(
                at: fileURL,
                replacingItemAt: repositoryURL.appendingPathComponent(localRelativePath),
            )
            print("Saved \(localRelativePath)")
        }
    }

    static func checkForUnusedLocalizations(in repositoryURL: URL) throws {
        try checkForUnusedLocalizations(
            in: repositoryURL.appendingPathComponent(Self.relativeDirectoryPath),
            suffix: "",
            expectedLocalizations: languageMap.flatMap { $1 } + extraEnglishLanguages + ["en-US"],
        )
    }
}