mirror of
https://github.com/libretro/virtualjaguar-libretro.git
synced 2026-11-07 04:36:00 -10:00
libretro_core_options_intl.h has been included behind HAVE_NO_LANGEXTRA all along but is an empty stub -- no arrays, just RETRO_LANGUAGE_* placeholder comments -- so option labels have never been translatable. This adds the standard libretro Crowdin pipeline that fills it. The intl/ toolchain and the three workflows are copies of the RetroArch example_translation sample. Placeholders are filled for this repo: core name virtualjaguar-libretro, both headers at the repo root. Three deliberate deviations from the sample: - The workflows watch and write develop, not the default branch. This repo is GitFlow and master is release-only; the sample assumes one default branch, so on a schedule it would check out and commit straight to master. - The `on:` blocks are rewritten. The sample ships `on:`, `workflow_dispatch` and `schedule:` as sibling lines, which is not valid YAML -- the manual-dispatch trigger is silently lost. - intl/activate.py is dropped. It is a one-shot placeholder filler that targets the older crowdin_prep.yml / crowdin_translate.yml names and raises against the current sample's filenames. The placeholders here are already filled, so it had no remaining use. The sync step also gained a `git diff --cached --quiet ||` guard: the generator only rewrites the header when a translation actually changed, so a quiet week would otherwise fail the run on an empty commit. options_intl[] stays all-NULL. The generator writes only the intl header; enabling a language means replacing its NULL with &options_xx by hand once translations exist. That is manual upstream too, and is documented rather than pre-empted -- referencing symbols that do not exist yet would not compile. This unblocks now that #257 froze the option strings, so translators are not handed text that is about to change. Timing: sync runs Fridays 06:35 UTC. docs/core-option-translations.md covers the pipeline, the enable-a-language step, and the four setup steps that need libretro org access (Crowdin token -> CROWDIN_API_KEY secret -> initial setup run -> sync run). Until that secret exists both workflows fail on an empty key, which is the intended visible "not set up yet" state. Co-Authored-By: Claude Opus 5 <[email protected]>
94 lines
3.4 KiB
Python
94 lines
3.4 KiB
Python
#!/usr/bin/env python3
|
|
|
|
import re
|
|
import os
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
import urllib.request
|
|
import zipfile
|
|
import core_option_translation as t
|
|
|
|
# -------------------- MAIN -------------------- #
|
|
|
|
if __name__ == '__main__':
|
|
# Check Crowdin API Token and core name
|
|
try:
|
|
API_KEY = sys.argv[1]
|
|
CORE_NAME = t.clean_file_name(sys.argv[2])
|
|
except IndexError as e:
|
|
print('Please provide Crowdin API Token and core name!')
|
|
raise e
|
|
|
|
DIR_PATH = t.os.path.dirname(t.os.path.realpath(__file__))
|
|
YAML_PATH = t.os.path.join(DIR_PATH, 'crowdin.yaml')
|
|
|
|
# Apply Crowdin API Key
|
|
with open(YAML_PATH, 'r') as crowdin_config_file:
|
|
crowdin_config = crowdin_config_file.read()
|
|
crowdin_config = re.sub(r'"api_token": "_secret_"',
|
|
f'"api_token": "{API_KEY}"',
|
|
crowdin_config, 1)
|
|
crowdin_config = re.sub(r'/_core_name_',
|
|
f'/{CORE_NAME}'
|
|
, crowdin_config)
|
|
with open(YAML_PATH, 'w') as crowdin_config_file:
|
|
crowdin_config_file.write(crowdin_config)
|
|
|
|
try:
|
|
# Download Crowdin CLI
|
|
jar_name = 'crowdin-cli.jar'
|
|
jar_path = t.os.path.join(DIR_PATH, jar_name)
|
|
crowdin_cli_file = 'crowdin-cli.zip'
|
|
crowdin_cli_url = 'https://downloads.crowdin.com/cli/v3/' + crowdin_cli_file
|
|
crowdin_cli_path = t.os.path.join(DIR_PATH, crowdin_cli_file)
|
|
|
|
if not os.path.isfile(t.os.path.join(DIR_PATH, jar_name)):
|
|
print('download crowdin-cli.jar')
|
|
urllib.request.urlretrieve(crowdin_cli_url, crowdin_cli_path)
|
|
with zipfile.ZipFile(crowdin_cli_path, 'r') as zip_ref:
|
|
jar_dir = t.os.path.join(DIR_PATH, zip_ref.namelist()[0])
|
|
for file in zip_ref.namelist():
|
|
if file.endswith(jar_name):
|
|
jar_file = file
|
|
break
|
|
zip_ref.extract(jar_file, path=DIR_PATH)
|
|
os.rename(t.os.path.join(DIR_PATH, jar_file), jar_path)
|
|
os.remove(crowdin_cli_path)
|
|
shutil.rmtree(jar_dir)
|
|
|
|
print('download translation *.json')
|
|
subprocess.run(['java', '-jar', jar_path, 'download', '--config', YAML_PATH])
|
|
|
|
# Reset Crowdin API Key
|
|
with open(YAML_PATH, 'r') as crowdin_config_file:
|
|
crowdin_config = crowdin_config_file.read()
|
|
crowdin_config = re.sub(r'"api_token": ".*?"',
|
|
'"api_token": "_secret_"',
|
|
crowdin_config, 1)
|
|
|
|
# TODO this is NOT safe!
|
|
crowdin_config = re.sub(re.escape(f'/{CORE_NAME}'),
|
|
'/_core_name_',
|
|
crowdin_config)
|
|
|
|
with open(YAML_PATH, 'w') as crowdin_config_file:
|
|
crowdin_config_file.write(crowdin_config)
|
|
|
|
except Exception as e:
|
|
# Try really hard to reset Crowdin API Key
|
|
with open(YAML_PATH, 'r') as crowdin_config_file:
|
|
crowdin_config = crowdin_config_file.read()
|
|
crowdin_config = re.sub(r'"api_token": ".*?"',
|
|
'"api_token": "_secret_"',
|
|
crowdin_config, 1)
|
|
|
|
# TODO this is NOT safe!
|
|
crowdin_config = re.sub(re.escape(f'/{CORE_NAME}'),
|
|
'/_core_name_',
|
|
crowdin_config)
|
|
|
|
with open(YAML_PATH, 'w') as crowdin_config_file:
|
|
crowdin_config_file.write(crowdin_config)
|
|
raise e
|