-
Notifications
You must be signed in to change notification settings - Fork 52
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add automatic Crowdin synchronization (#205)
- Loading branch information
1 parent
eb57e0c
commit ae10991
Showing
19 changed files
with
30,253 additions
and
228 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
# Prepare source texts & upload them to Crowdin | ||
|
||
name: Crowdin Source Texts Upload | ||
|
||
# on change to the English texts | ||
on: | ||
push: | ||
branches: | ||
- master | ||
paths: | ||
- 'libretro_core_options.h' | ||
|
||
jobs: | ||
upload_source_file: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Setup Java JDK | ||
uses: actions/setup-java@v1 | ||
with: | ||
java-version: 1.8 | ||
|
||
- name: Setup Python | ||
uses: actions/setup-python@v2 | ||
|
||
- name: Checkout | ||
uses: actions/checkout@v2 | ||
|
||
- name: Upload Source | ||
shell: bash | ||
env: | ||
CROWDIN_API_KEY: ${{ secrets.CROWDIN_API_KEY }} | ||
run: | | ||
python3 intl/upload_workflow.py $CROWDIN_API_KEY "beetle-pce-fast-libretro" "libretro_core_options.h" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
# Download translations form Crowdin & Recreate libretro_core_options_intl.h | ||
|
||
name: Crowdin Translation Integration | ||
|
||
on: | ||
schedule: | ||
# please choose a random time & weekday to avoid all repos synching at the same time | ||
- cron: '15 21 * * 5' # Fridays at 9:15 PM, UTC | ||
|
||
jobs: | ||
create_intl_file: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Setup Java JDK | ||
uses: actions/setup-java@v1 | ||
with: | ||
java-version: 1.8 | ||
|
||
- name: Setup Python | ||
uses: actions/setup-python@v2 | ||
|
||
- name: Checkout | ||
uses: actions/checkout@v2 | ||
with: | ||
persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal access token. | ||
fetch-depth: 0 # otherwise, there would be errors pushing refs to the destination repository. | ||
|
||
- name: Create intl file | ||
shell: bash | ||
env: | ||
CROWDIN_API_KEY: ${{ secrets.CROWDIN_API_KEY }} | ||
run: | | ||
python3 intl/download_workflow.py $CROWDIN_API_KEY "beetle-pce-fast-libretro" "libretro_core_options_intl.h" | ||
- name: Commit files | ||
run: | | ||
git config --local user.email "github-actions@github.com" | ||
git config --local user.name "github-actions[bot]" | ||
git add intl/*_workflow.py "libretro_core_options_intl.h" | ||
git commit -m "Fetch translations & Recreate libretro_core_options_intl.h" | ||
- name: GitHub Push | ||
uses: ad-m/github-push-action@v0.6.0 | ||
with: | ||
github_token: ${{ secrets.GITHUB_TOKEN }} | ||
branch: ${{ github.ref }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
__pycache__ | ||
crowdin-cli.jar | ||
*.h | ||
*.json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
#!/usr/bin/env python3 | ||
|
||
import os | ||
import glob | ||
import random as r | ||
|
||
# -------------------- MAIN -------------------- # | ||
|
||
if __name__ == '__main__': | ||
DIR_PATH = os.path.dirname(os.path.realpath(__file__)) | ||
if os.path.basename(DIR_PATH) != "intl": | ||
raise RuntimeError("Script is not in intl folder!") | ||
|
||
BASE_PATH = os.path.dirname(DIR_PATH) | ||
WORKFLOW_PATH = os.path.join(BASE_PATH, ".github", "workflows") | ||
PREP_WF = os.path.join(WORKFLOW_PATH, "crowdin_prep.yml") | ||
TRANSLATE_WF = os.path.join(WORKFLOW_PATH, "crowdin_translate.yml") | ||
CORE_NAME = os.path.basename(BASE_PATH) | ||
CORE_OP_FILE = os.path.join(BASE_PATH, "**", "libretro_core_options.h") | ||
|
||
core_options_hits = glob.glob(CORE_OP_FILE, recursive=True) | ||
|
||
if len(core_options_hits) == 0: | ||
raise RuntimeError("libretro_core_options.h not found!") | ||
elif len(core_options_hits) > 1: | ||
print("More than one libretro_core_options.h file found:\n\n") | ||
for i, file in enumerate(core_options_hits): | ||
print(f"{i} {file}\n") | ||
|
||
while True: | ||
user_choice = input("Please choose one ('q' will exit): ") | ||
if user_choice == 'q': | ||
exit(0) | ||
elif user_choice.isdigit(): | ||
core_op_file = core_options_hits[int(user_choice)] | ||
break | ||
else: | ||
print("Please make a valid choice!\n\n") | ||
else: | ||
core_op_file = core_options_hits[0] | ||
|
||
core_intl_file = os.path.join(os.path.dirname(core_op_file.replace(BASE_PATH, ''))[1:], | ||
'libretro_core_options_intl.h') | ||
core_op_file = os.path.join(os.path.dirname(core_op_file.replace(BASE_PATH, ''))[1:], | ||
'libretro_core_options.h') | ||
minutes = r.randrange(0, 59, 5) | ||
hour = r.randrange(0, 23) | ||
|
||
with open(PREP_WF, 'r') as wf_file: | ||
prep_txt = wf_file.read() | ||
|
||
prep_txt = prep_txt.replace("<CORE_NAME>", CORE_NAME) | ||
prep_txt = prep_txt.replace("<PATH/TO>/libretro_core_options.h", | ||
core_op_file) | ||
with open(PREP_WF, 'w') as wf_file: | ||
wf_file.write(prep_txt) | ||
|
||
|
||
with open(TRANSLATE_WF, 'r') as wf_file: | ||
translate_txt = wf_file.read() | ||
|
||
translate_txt = translate_txt.replace('<0-59>', f"{minutes}") | ||
translate_txt = translate_txt.replace('<0-23>', f"{hour}") | ||
translate_txt = translate_txt.replace('# Fridays at , UTC', | ||
f"# Fridays at {hour%12}:{minutes} {'AM' if hour < 12 else 'PM'}, UTC") | ||
translate_txt = translate_txt.replace("<CORE_NAME>", CORE_NAME) | ||
translate_txt = translate_txt.replace('<PATH/TO>/libretro_core_options_intl.h', | ||
core_intl_file) | ||
with open(TRANSLATE_WF, 'w') as wf_file: | ||
wf_file.write(translate_txt) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
import re | ||
|
||
# 0: full struct; 1: up to & including first []; 2: content between first {} | ||
p_struct = re.compile(r'(struct\s*[a-zA-Z0-9_\s]+\[])\s*' | ||
r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+)\s*)*' | ||
r'=\s*' # = | ||
r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+)\s*)*' | ||
r'{((?:.|[\r\n])*?)\{\s*NULL,\s*NULL,\s*NULL\s*(?:.|[\r\n])*?},?(?:.|[\r\n])*?};') # captures full struct, it's beginning and it's content | ||
# 0: type name[]; 1: type; 2: name | ||
p_type_name = re.compile(r'(retro_core_option_[a-zA-Z0-9_]+)\s*' | ||
r'(option_cats([a-z_]{0,8})|option_defs([a-z_]*))\s*\[]') | ||
# 0: full option; 1: key; 2: description; 3: additional info; 4: key/value pairs | ||
p_option = re.compile(r'{\s*' # opening braces | ||
r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*' | ||
r'(\".*?\"|' # key start; group 1 | ||
r'[a-zA-Z0-9_]+\s*\((?:.|[\r\n])*?\)|' | ||
r'[a-zA-Z0-9_]+\s*\[(?:.|[\r\n])*?]|' | ||
r'[a-zA-Z0-9_]+\s*\".*?\")\s*' # key end | ||
r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*' | ||
r',\s*' # comma | ||
r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*' | ||
r'(\".*?\")\s*' # description; group 2 | ||
r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*' | ||
r',\s*' # comma | ||
r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*' | ||
r'((?:' # group 3 | ||
r'(?:NULL|\"(?:.|[\r\n])*?\")\s*' # description in category, info, info in category, category | ||
r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*' | ||
r',?\s*' # comma | ||
r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*' | ||
r')+)' | ||
r'(?:' # defs only start | ||
r'{\s*' # opening braces | ||
r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*' | ||
r'((?:' # key/value pairs start; group 4 | ||
r'{\s*' # opening braces | ||
r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*' | ||
r'(?:NULL|\".*?\")\s*' # option key | ||
r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*' | ||
r',\s*' # comma | ||
r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*' | ||
r'(?:NULL|\".*?\")\s*' # option value | ||
r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*' | ||
r'}\s*' # closing braces | ||
r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*' | ||
r',?\s*' # comma | ||
r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*' | ||
r')*)' # key/value pairs end | ||
r'}\s*' # closing braces | ||
r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*' | ||
r',?\s*' # comma | ||
r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*' | ||
r'(?:' # defaults start | ||
r'(?:NULL|\".*?\")\s*' # default value | ||
r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*' | ||
r',?\s*' # comma | ||
r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*' | ||
r')*' # defaults end | ||
r')?' # defs only end | ||
r'},') # closing braces | ||
# analyse option group 3 | ||
p_info = re.compile(r'(NULL|\"(?:.|[\r\n])*?\")\s*' # description in category, info, info in category, category | ||
r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*' | ||
r',') | ||
p_info_cat = re.compile(r'(NULL|\"(?:.|[\r\n])*?\")') | ||
# analyse option group 4 | ||
p_key_value = re.compile(r'{\s*' # opening braces | ||
r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*' | ||
r'(NULL|\".*?\")\s*' # option key; 1 | ||
r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*' | ||
r',\s*' # comma | ||
r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*' | ||
r'(NULL|\".*?\")\s*' # option value; 2 | ||
r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*' | ||
r'}') | ||
|
||
p_masked = re.compile(r'([A-Z_][A-Z0-9_]+)\s*(\"(?:"\s*"|\\\s*|.)*\")') | ||
|
||
p_intl = re.compile(r'(struct retro_core_option_definition \*option_defs_intl\[RETRO_LANGUAGE_LAST]) = {' | ||
r'((?:.|[\r\n])*?)};') | ||
p_set = re.compile(r'static INLINE void libretro_set_core_options\(retro_environment_t environ_cb\)' | ||
r'(?:.|[\r\n])*?};?\s*#ifdef __cplusplus\s*}\s*#endif') | ||
|
||
p_yaml = re.compile(r'"project_id": "[0-9]+".*\s*' | ||
r'"api_token": "([a-zA-Z0-9]+)".*\s*' | ||
r'"base_path": "\./intl".*\s*' | ||
r'"base_url": "https://api\.crowdin\.com".*\s*' | ||
r'"preserve_hierarchy": true.*\s*' | ||
r'"files": \[\s*' | ||
r'\{\s*' | ||
r'"source": "/_us/\*\.json",.*\s*' | ||
r'"translation": "/_%two_letters_code%/%original_file_name%",.*\s*' | ||
r'"skip_untranslated_strings": true.*\s*' | ||
r'},\s*' | ||
r']') |
Oops, something went wrong.