Hello Transifex Community!
In this Script Chef special, we’ll be cooking up an interactive utility that helps you fetch translations for a specific string hash across multiple projects, resources, and languages within your Transifex organization.
When managing multiple projects, finding translations for a specific string can feel like searching for a needle in a haystack. This handy Python script lets you interactively narrow down your search, making it easy to pull up exactly what you need, when you need it.
Let’s break down the recipe step-by-step.
Ingredients
Before we get started, here’s what you’ll need for this recipe:
- API Token: To authenticate your Transifex API requests.
- Organization Slug: The slug for your organization in Transifex.
- Project Slugs (optional): Specific projects where you want to look up the translations.
- Language Codes (optional): The languages you want translations for.
- Resource Slugs (optional): Specific resources for filtering the translations.
- Source String Hash: The hash of the source string for which you need translations.
Required Libraries
Make sure you have the necessary libraries installed. Run this command to install them:
pip install transifex.api
Step-by-Step Instructions
Step 1: Setting Up Your Utensils (Imports)
To interact with the Transifex API, we need to import the right tools:
import itertools
from transifex.api import transifex_api
from transifex.api.jsonapi import JsonApiException
Step 2: Prompting for Ingredients (Interactive User Input)
We’ll use a prompt
function to interactively gather input from the user. This function will keep asking for valid input until a valid response is provided.
def prompt(msg, validate=None):
"""
Repeatedly try to get an answer from the user
"""
while True:
answer = input(msg).strip()
if answer and (validate is None or answer in validate):
return answer
Step 3: Cooking the Main Course (Main Function)
The main function will prompt the user for their API token, organization slug, and other parameters such as project slugs, language codes, resource slugs, and the source string hash. Based on the user’s input, the script will fetch translations accordingly.
3.1: Gathering Input for API Token and Organization
We first prompt for the API token and organization slug to set up the connection to the Transifex API.
def main():
"""Main function"""
token = prompt("Please enter your API token: ")
transifex_api.setup(auth=token)
organization_slug = prompt("Please enter your Organization slug: ")
organization = transifex_api.Organization.get(slug=organization_slug)
3.2: Project and Resource Selection
Next, the script asks whether the user wants to fetch translations from all projects or specific ones, and similarly for resources. The input is then processed to fetch only the relevant data.
project_answer = prompt(
"Do you want translations for [a]ll projects or [s]pecific ones? [a/s]:",
validate=("a", "s"),
)
if project_answer == "s":
project_slugs = prompt(
"Please enter the project slugs, separate them with a comma (,): "
)
project_slugs = project_slugs.split(",")
project_slugs = [project_slug.strip() for project_slug in project_slugs]
resource_answer = prompt(
"Do you want translations for [a]ll resources or [s]pecific resources? [a/s]:",
validate=("a", "s"),
)
if resource_answer == "s":
resource_slugs = prompt(
"Please enter the resources slugs, separate them with a comma (,): "
)
resource_slugs = resource_slugs.split(",")
resource_slugs = [resource_slug.strip() for resource_slug in resource_slugs]
3.3: Language Selection
The script then asks whether the user wants translations for all languages or specific ones, and processes the input.
language_answer = prompt(
"Do you want translations files for [a]ll languages, or for [s]pecific languages? [a/s]:",
validate=("a", "s"),
)
if language_answer == "s":
language_codes = prompt(
"Please enter the language codes, separate them with a comma (,): "
)
language_codes = language_codes.split(",")
language_codes = [language_code.strip() for language_code in language_codes]
3.4: Fetching the Translations
Finally, we loop through the specified projects, resources, and languages, fetching translations for the given string hash. The script handles multiple projects and languages using itertools.product()
.
string_hash = prompt("Please enter the source string hash: ")
if project_answer == "a":
projects = list(organization.fetch("projects").all())
elif project_answer == "s":
projects = [
project
for project in organization.fetch("projects").all()
if project.slug in project_slugs
]
for project in projects:
print(f"Translations for Project {project.slug}")
if resource_answer == "a":
resources = list(project.fetch("resources").all())
elif resource_answer == "s":
resources = [
resource
for resource in project.fetch("resources").all()
if resource.slug in resource_slugs
]
if language_answer == "a":
languages = list(project.fetch("languages").all())
elif language_answer == "s":
languages = [
language
for language in project.fetch("languages").all()
if language.code in language_codes
]
for resource, language in itertools.product(resources, languages):
print(
f"- Project: {project.slug} / "
f"Resource: {resource.slug} / "
f"Language: {language.code}: "
)
resource_translation_id = (
f"o:{organization_slug}:"
f"p:{project.slug}:"
f"r:{resource.slug}:"
f"s:{string_hash}:"
f"l:{language.code}"
)
try:
resource_translation = transifex_api.ResourceTranslation.get(
resource_translation_id, include=["resource_string"]
)
except JsonApiException.get("not_found") as exc:
print(", ".join((error["detail"] for error in exc.filter("not_found"))))
else:
if (resource_translation.strings) is None:
print(resource_translation.strings)
else:
print(resource_translation.strings["other"])
Step 4: Serving the Final Dish
Once all the translations are fetched, the script prints them out, along with relevant project, resource, and language details.
if __name__ == "__main__":
main()
Final Thoughts
This script helps you quickly fetch translations for a specific string hash across multiple projects and languages. Whether you’re working with a handful of projects or managing a large number of resources, this interactive tool simplifies the process.
Give it a try and feel free to tweak it to suit your needs! Happy coding, and stay tuned for more recipes in the Script Chef series.