~aleteoryx/muditaos

ref: 5b0ea283eb9cc6e453cf9bae898b98e1f65038f0 muditaos/tools/verify_translations.py -rwxr-xr-x 4.8 KiB
5b0ea283 — Adam Wulkiewicz [BH-000] Update changelog for 1.8.2 and 1.9.0 2 years ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#!/usr/bin/python3
# Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
# For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

import collections
import os
import os.path as path
import argparse
import json
import sys
import logging
import textwrap

logging.basicConfig(level=logging.DEBUG, format='%(levelname)s: %(message)s')
logger = logging.getLogger(__name__)
handler = logging.StreamHandler(sys.stdout)
logger.addHandler(handler)


def detect_duplicate_keys(list_of_pairs: list):
    key_count = collections.Counter(k for k, v in list_of_pairs)
    duplicate_keys = ', '.join(k for k, v in key_count.items() if v > 1)

    if duplicate_keys:
        raise ValueError(duplicate_keys)


def validate_data(list_of_pairs: list):
    detect_duplicate_keys(list_of_pairs)
    # More detection, each of them will raise exception upon invalid
    # data
    return dict(list_of_pairs)


def perform_on_files_from_path(json_path: path, operation):
    dir_list = os.listdir(json_path)
    ret = 0

    for file in dir_list:
        file_path = path.join(json_path, file)
        with open(file_path) as json_file:
            ret |= operation(file_path, json_file)
    return ret


def check_duplicates(file_path: path, json_file):
    try:
        _ = json.load(json_file, object_pairs_hook=validate_data)
    except ValueError as e:
        dup_list = str(e).split(',')
        logger.warning(f"[{path.basename(file_path)}]: duplicate {len(dup_list)}: {dup_list}")
        return 1
    return 0


def check_empty_entries(file_path: path, json_file):
    json_data = json.load(json_file)
    empty_entries = [entry for entry in json_data if len(str(json_data[entry])) == 0]
    if empty_entries:
        logger.warning(f"[{path.basename(file_path)}]: empty entries {len(empty_entries)}: {empty_entries}")
        return 1
    return 0


def get_all_keys_from_path(json_path: path):
    dir_list = os.listdir(json_path)
    json_keys = []

    # iterate to get all possible keys and check for key duplicates
    for file in dir_list:
        file_path = path.join(json_path, file)

        with open(file_path) as json_file:
            json_data = json.load(json_file)
            json_keys.append(set(json_data))

    return set.union(*json_keys)


def check_missing_entries_from_path(json_path: path):
    ret = 0
    dir_list = os.listdir(json_path)
    all_keys = get_all_keys_from_path(json_path)

    # iterate to find missing keys
    for file in dir_list:
        file_path = path.join(json_path, file)
        with open(file_path) as json_file:
            json_data = json.load(json_file)
            missing_keys_in_file = all_keys.difference(set(json_data))
            if missing_keys_in_file:
                logger.warning(f"[{file}]: missing {len(missing_keys_in_file)}: {sorted(missing_keys_in_file)}")
                ret |= 1
    return ret


def fix_jsons(json_src_path: path, json_dst_path: path):
    dir_list = os.listdir(json_src_path)
    for file in dir_list:
        src_file_path = path.join(json_src_path, file)
        dst_file_path = path.join(json_dst_path, file)
        if not path.exists(json_dst_path):
            os.makedirs(json_dst_path)

        with open(src_file_path) as json_file, open(dst_file_path, 'w') as outfile:
            json_data = json.load(json_file)
            json.dump(json_data, outfile, indent=4, sort_keys=True)

    logger.info("Translation files fixed")


def main(args):
    ret = 0
    if args.fix:
        fix_jsons(args.src, args.dst)

    ret |= check_missing_entries_from_path(args.src)
    ret |= perform_on_files_from_path(args.src, check_empty_entries)
    ret |= perform_on_files_from_path(args.src, check_duplicates)
    return ret


if __name__ == "__main__":
    parser = argparse.ArgumentParser(
        prog='verify_translations',
        description='Script for checking the inconsistency of lang jsons',
        formatter_class=argparse.RawTextHelpFormatter)
    parser.add_argument('-s', '--src', metavar='path', help="source path to the json files", required=True)
    parser.add_argument('--fix', action='store_true', help=textwrap.dedent('''\
        fix the translation files: remove duplicates and sort
        WARNING! this will overwrite your destination files!
        
        Use with caution!'''))
    parser.add_argument('-d', '--dst', metavar='path', help="destination path for the fixed json files")
    parser.add_argument('-v', '--verbose', action='store_true')

    args = parser.parse_args()

    if args.fix and not args.dst:
        parser.error("The destination path must be specified")
        sys.exit(1)

    if args.verbose:
        logger.setLevel(logging.DEBUG)
    else:
        logger.setLevel(logging.CRITICAL)

    error_code = main(args)
    if error_code:
        logging.error("Verification failed")
    sys.exit(error_code)