From 9289cef0fd7494487208a6d24bc6904211ae8bba Mon Sep 17 00:00:00 2001 From: HenestrosaDev Date: Wed, 29 May 2024 13:47:29 +0200 Subject: [PATCH] Add support for multiple files and directories input --- README.md | 65 +++++++---- src/mobile_strings_converter/__init__.py | 2 +- src/mobile_strings_converter/__main__.py | 137 +++++++++++++++++++---- 3 files changed, 160 insertions(+), 44 deletions(-) diff --git a/README.md b/README.md index cbab79a..7f3bcea 100644 --- a/README.md +++ b/README.md @@ -125,7 +125,7 @@ In addition to being able to run this script on its own, it can also be installe ### Project Structure
- ASCII folder structure + ASCII directory structure ``` │ .gitignore @@ -289,29 +289,51 @@ Install the PyPI package by running `pip install mobile-strings-converter`. ### Running the Program -For basic use, you can run the following command: +To convert one file to another file: -```bash -python path/to/mobile_strings_converter.py *.[SUPPORTED_FILE_TYPE] -o *.[SUPPORTED_FILE_TYPE] +``` +python path/to/mobile_strings_converter.py *.[SUPPORTED_FILE_TYPE] -f *.[SUPPORTED_FILE_TYPE] +``` + +To include the comments of the `.xml`/`.strings` input file in the output file, add the `-p` (also `--print-comments`) flag. Note that it will be ignored for other input file types. + +``` +python path/to/mobile_strings_converter.py *.[SUPPORTED_FILE_TYPE] -f *.[SUPPORTED_FILE_TYPE] -p +``` + +To convert multiple files at once and save them to the specified directory passed in the `-d` flag, use the`-t` flag followed by the desired file type extension (e.g., `.json`). Note that the program will create the directory if it doesn't exist. + +``` +python path/to/mobile_strings_converter.py *.[SUPPORTED_FILE_TYPE] *.[SUPPORTED_FILE_TYPE] *.[SUPPORTED_FILE_TYPE] -d [DIR_PATH] -t [TARGET_TYPE] ``` -To include the comments of the `.xml`/`.strings` file in the output file, add the `-p` (also `--print-comments`) flag: +To convert supported files in a directory and its subdirectories and save them to a directory: -```bash -python path/to/mobile_strings_converter.py *.[SUPPORTED_FILE_TYPE] -o *.[SUPPORTED_FILE_TYPE] -p +``` +python path/to/mobile_strings_converter.py [INPUT_DIR_PATH] -d [OUTPUT_DIR_PATH] -t [TARGET_TYPE] +``` + +To convert supported files in multiple directories and their subdirectories and save them to a directory: + +``` +python path/to/mobile_strings_converter.py [INPUT_DIR_PATH_1] [INPUT_DIR_PATH_2] [INPUT_DIR_PATH_3] -d [OUTPUT_DIR_PATH] -t [TARGET_TYPE] ``` +For multiple file inputs and directories, the name of the files will be the same as the input file. For example, if there is a file named `spanish.xml` in a directory, the output file name will be `spanish.[TARGET_TYPE]` + See the [Generating a Spreadsheet in Google Sheets](#generating-a-spreadsheet-in-google-sheets) section to create a spreadsheet in your Google account. #### Script Flags -| Flag | Description | -|:----------------------------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `-h` or `--help` | Displays help text for the program | -| `-o` or `--output-filepath` | Specifies the filepath for storing the converted file. The file extension can be chosen from the list of supported file types mentioned [here](#about-the-project). | -| `-g` or `--google-sheets` | Followed by the name of the sheet, creates a new Google Sheets spreadsheet with the specified name. | -| `-c` or `--credentials` | Followed by the path to your `service_account.json` file is mandatory if you want to generate a spreadsheet in your Google account. | -| `-p` or `--print-comments` | The output file will contain all commented strings that were present in the original file (only applicable if the input file is a `.xml` or `.strings` file). Otherwise it will be ignored. | +| Flag | Description | +|:----------------------------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `-h` or `--help` | Displays help text for the program. | +| `-f` or `--output-filepath` | Path to save the converted file. Only works if only one input file is provided. The file extension can be chosen from [the list of supported file types](#file-types-supported). | +| `-d` or `--output-dir` | Directory where the converted files will be saved. Compatible with single and multiple input files as well as directories. The specified directory will be created if it does not already exist. | +| `-t` or `--target-type` | Target file type to convert the files (e.g., .pdf, .json). Required if multiple file paths or the `--output-dir` is specified. | +| `-g` or `--google-sheets` | If provided, a Google spreadsheet will be created in your Google account. You must pass the `service_account.json` with the `-c` flag. | +| `-c` or `--credentials` | `service_account.json` filepath. Mandatory if you want to generate a spreadsheet in your Google account. You can learn how to generate it in the [Generating a Spreadsheet in Google Sheets](#generating-a-spreadsheet-in-google-sheets) section. | +| `-p` or `--print-comments` | If provided, the commented strings will be printed in the output file. Only valid for input files of type `.xml` or `.strings`. Otherwise it is ignored. |

(back to top)

@@ -348,15 +370,17 @@ Alternatively, you can create an `.xlsx` file and open it in Google Sheets if yo Once you have the `service_account.json` file, you can create a spreadsheet in Google Sheets by running the following command: -```bash -python path/to/mobile_strings_converter.py *.[SUPPORTED_FILE_TYPE] -g [SHEET_NAME] -c path/to/service_account.json +``` +python path/to/mobile_strings_converter.py *.[SUPPORTED_FILE_TYPE] -g -c path/to/service_account.json ``` If you want to generate an output file along with the spreadsheet, run this: -```bash -python path/to/mobile_strings_converter.py *.[SUPPORTED_FILE_TYPE] -g [SHEET_NAME] -c path/to/service_account.json -o *.[SUPPORTED_FILE_TYPE] ``` +python path/to/mobile_strings_converter.py *.[SUPPORTED_FILE_TYPE] -g -c path/to/service_account.json -o *.[SUPPORTED_FILE_TYPE] +``` + +The name of the sheet will be the same as the name of the input file. #### Using the `to_google_sheets` Function in Your Project @@ -407,8 +431,9 @@ to_google_sheets( ## Roadmap - [x] Add support for converting a file (not `.xml` or `.strings`) into a strings resource file (`.xml` or `.strings`). -- [ ] Add support for multiple files input. -- [ ] Add support for accepting the path to a folder as input. +- [x] Add support for multiple files input. +- [x] Add support for accepting the path to a directory as input. +- [x] Add support for accepting the path to a directory as output. - [ ] Make a web version. You can propose a new feature creating an [issue](https://github.com/HenestrosaDev/mobile-strings-converter/new/choose). diff --git a/src/mobile_strings_converter/__init__.py b/src/mobile_strings_converter/__init__.py index 4f952d4..4816e75 100644 --- a/src/mobile_strings_converter/__init__.py +++ b/src/mobile_strings_converter/__init__.py @@ -7,7 +7,7 @@ from .converter import convert_strings, to_google_sheets # Constants -__version__ = "0.1.3" +__version__ = "0.1.4" __author__ = "José Carlos López Henestrosa" __license = "MIT" diff --git a/src/mobile_strings_converter/__main__.py b/src/mobile_strings_converter/__main__.py index 59fd2b6..c71fcf4 100644 --- a/src/mobile_strings_converter/__main__.py +++ b/src/mobile_strings_converter/__main__.py @@ -1,33 +1,64 @@ import argparse +import os from pathlib import Path from console_style import ConsoleStyle from converter import convert_strings, to_google_sheets +def get_filepaths_from_dir(directory, extensions): + """Return a list of filepaths in the directory matching the given extensions.""" + matched_files = [] + for root, _, files in os.walk(directory): + for file in files: + if file.endswith(tuple(extensions)): + matched_files.append(Path(root) / file) + + return matched_files + + def main(): parser = argparse.ArgumentParser( description="Takes input and output files from console." ) parser.add_argument( - "input_filepath", + "input_paths", type=str, - help=".xml or .strings filepath that contains the strings.", + nargs="+", # Accept one or more values + help="File paths or directories containing supported file types to be " + "converted.", ) parser.add_argument( - "-o", + "-f", "--output-filepath", required=False, type=str, - help="Output filepath where you want to store the converted file. It can be a " - "CSV, HTML, iOS strings file, MD, JSON, ODS, PDF, XLSX, XML or YAML file.", + help="Path to save the converted file. Only works if only one input file " + "is provided. See the README for a list of supported file types.", + ) + parser.add_argument( + "-d", + "--output-dir", + required=False, + type=str, + help="Directory where the converted files will be saved. Compatible with " + "single and multiple input files as well as directories. The specified " + "directory will be created if it does not already exist.", + ) + parser.add_argument( + "-t", + "--target-type", + type=str, + help="Target file type to convert the files (e.g., .pdf, .json). Required if " + "multiple file paths or the `--output-dir` is specified.", ) parser.add_argument( "-g", "--google-sheets", required=False, - type=str, - help="Creates a spreadsheet in Google Sheets with the name passed as argument.", + action="store_true", + help="If provided, a Google spreadsheet will be created in your Google " + "account. You must pass the `service_account.json` with the -c flag.", ) parser.add_argument( "-c", @@ -43,34 +74,94 @@ def main(): "--print-comments", required=False, action="store_true", - help="If called, indicates that commented strings will be printed in the " - "output file.", + help="If provided, the commented strings will be printed in the output file. " + "Only valid for input files of type `.xml` or `.strings`. Otherwise it is " + "ignored.", ) + args = parser.parse_args() - input_filepath = Path(args.input_filepath) + # Check if the output-extension argument is provided when output-dir is specified + if args.output_dir and not args.target_type: + raise ValueError( + f"{ConsoleStyle.RED}--output-dir requires --output-extension." + f"{ConsoleStyle.END}" + ) + + allowed_extensions = [ + ".csv", + ".xlsx", + ".ods", + ".md", + ".json", + ".yaml", + ".html", + ".strings", + ".xml", + ".pdf", + ] + + input_filepaths = [] + output_dir = None + + for path in args.input_paths: + if os.path.isdir(path): + # If it's a directory, get all matching files + input_filepaths.extend(get_filepaths_from_dir(path, allowed_extensions)) + elif os.path.isfile(path) and path.endswith(tuple(allowed_extensions)): + # If it's a file with an allowed extension, add it to the list + input_filepaths.append(Path(path)) + else: + print( + f"{ConsoleStyle.YELLOW}Skipping unsupported file or path: {path}" + f"{ConsoleStyle.END}" + ) + + # Ensure the correct output options are used + if args.output_filepath: + if len(input_filepaths) > 1: + raise ValueError( + "Cannot use --output-filepath with multiple input files. Use " + "--output-dir instead." + ) + output_path = Path(args.output_filepath) + output_path.parent.mkdir(parents=True, exist_ok=True) + elif args.output_dir: + output_dir = Path(args.output_dir) + output_dir.mkdir(parents=True, exist_ok=True) + else: + raise ValueError( + f"{ConsoleStyle.RED}You must specify an output path with the " + f"-f or -d flag.{ConsoleStyle.END}" + ) if args.google_sheets and not args.credentials: - print( - f"{ConsoleStyle.RED}Error: You need to pass the path of the " + raise ValueError( + f"{ConsoleStyle.RED}You need to pass the path of the " f"`service_account.json` file to generate a Sheet.{ConsoleStyle.END}" ) - return elif not args.google_sheets and args.credentials: - print( - f"{ConsoleStyle.RED}Error: You need to pass the name of the Sheet to be " + raise ValueError( + f"{ConsoleStyle.RED}You need to pass the name of the Sheet to be " f"generated.{ConsoleStyle.END}" ) - return elif args.google_sheets and args.credentials: - to_google_sheets( - input_filepath, - sheet_name=args.google_sheets, - credentials_filepath=Path(args.credentials), - with_comments=args.print_comments, - ) + for input_filepath in input_filepaths: + to_google_sheets( + args.input_filepath, + sheet_name=Path(input_filepath).stem, + credentials_filepath=Path(args.credentials), + with_comments=args.print_comments, + ) + + for input_filepath in input_filepaths: + if args.output_filepath: + output_filepath = Path(args.output_filepath) + else: + output_filename = Path(input_filepath).stem + args.target_type + output_filepath = output_dir / output_filename - convert_strings(input_filepath, Path(args.output_filepath), args.print_comments) + convert_strings(input_filepath, output_filepath, args.print_comments) if __name__ == "__main__":