Unable to translate certain strings from rails console

Infos:

  • Used Zammad version: 6.3.1-1718620481.9d65e987.jammy
  • Used Zammad installation type: package
  • Operating system: Ubuntu 22.04
  • Browser + version: Firefox 127.0 (64-bit)

Expected behavior:

  • Use rails console to add custom translations for all strings

Actual behavior:

  • It is possible to translate certain strings but not all of them
  • e.g. Organization does not work

  • Same for
    • My Organization Tickets
    • Zammad is currently in maintenance mode. Only administrators can log in. Please wait until the maintenance window is over.
  • It works for Customer or custom states
    • Translation.create_if_not_exists(:locale => 'de-de', :source => 'Customer ', :target => 'DSB', created_by_id: 1, updated_by_id: 1)

Steps to reproduce the behavior:

  • Open the Rails console zammad run rails c
  • Try to translate withTranslation.create_if_not_exists(:locale => 'de-de', :source => "Organization", :target => "Schule", created_by_id: 1, updated_by_id: 1)

Any pointer is greatly appreciated

Best,
Skip

I also tried to push it through the API but without luck :pensive:

[
    {
        "locale": "de-de",
        "source": "Organization",
        "target": "Schule",
        "target_initial": "Organisation",
        "is_synchronized_from_codebase": true,
        "synchronized_from_translation_file": "i18n/zammad.de-de.po",
        "updated_by_id": 1,
        "created_by_id": 1,
        "created_at": "2024-04-23T10:05:32.212Z",
        "updated_at": "2024-04-23T10:05:32.212Z"
    }
]

Probably because “Organization” is an already translated attribute? Have you tried switching your profile language to the target language? “Organization” gets translated, as well as the maintenance page text.

I agree, it is already translated to Organisation in german.
But I want to change that to Schule

It works with Customer which is Kunde but I can translate it to DSB using the rails console.

That is weird, as this translation should already exist as well. You might need to look into replacing the existing translations instead of trying to create new ones with the create_if_not_exists function, because it should already exist and fail to create a new one, but that is just my interpretation based on very basic Rails commandline skills.

Very weird :grin:

Also because Customer also already exists, but it is possible to change it’s translation with create_if_not_exist

Now I tried with create_or_update but instead of updating the translation with id 120588


and it is generating random translations

https://admin-docs.zammad.org/en/latest/system/translations.html

Thank you for the link

Since I am looking to automate, replicate and make installations of Zammad reproducible and auditable, I am looking for a more devops or automated way to do so and going into a GUI and manually adding translation is far from a reproducible way of setting up a system.

Is there no other way at this point to use a script or APIs to add translations? It worked very well for other translations

I was told by developers that the rails console variant is not supported.
Reverse engineer what Zamamd does in the background when you use the UI I guess.

Beside of that there’s just the UI to use. Anything beside of that is technically not supported.

I see, thanks for the info

If anyone is interested this is my quick hack to solve this using the API

import csv
import requests
import logging
import os
import urllib3

# Suppress only the single InsecureRequestWarning from urllib3 needed
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)


API_URL = 'https://example.com/api/v1/translations'
API_TOKEN = 'yourtoken'

headers = {
    'Authorization': f'Token token={API_TOKEN}',
    'Content-Type': 'application/json'
}


def fetch_all_translations():
    translations = []
    page = 1
    per_page = 50  # Adjust the per_page value based on the API's pagination settings
    while True:
        response = requests.get(f"{API_URL}?page={page}&per_page={per_page}", headers=headers, verify=False)
        if response.status_code == 200:
            data = response.json()
            translations.extend(data)
            if len(data) < per_page:
                break  # Exit the loop if we have fetched all pages
            page += 1
        else:
            logger.error(f"Failed to fetch translations. Status code: {response.status_code}, Response: {response.text}")
            break
    return translations

def find_translation_id(translations, locale, source):
    for translation in translations:
        if translation['locale'] == locale and translation['source'] == source:
            return translation['id']
    return None

def update_translation(translation_id, target):
    data = {
        'target': target
    }
    response = requests.put(f"{API_URL}/{translation_id}", json=data, headers=headers, verify=False)
    if response.status_code == 200:
        logger.info(f"Translation ID '{translation_id}' updated successfully.")
    else:
        logger.error(f"Failed to update translation ID '{translation_id}'. Status code: {response.status_code}, Response: {response.text}")

def add_translation(locale, source, target):
    data = {
        'locale': locale,
        'source': source,
        'target': target
    }
    response = requests.post(API_URL, json=data, headers=headers, verify=False)
    if response.status_code == 201:
        logger.info(f"Translation for '{source}' added successfully.")
    else:
        logger.error(f"Failed to add translation for '{source}'. Status code: {response.status_code}, Response: {response.text}")

def add_or_update_translations_from_csv(csv_file):
    translations = fetch_all_translations()
    with open(csv_file, 'r', encoding='utf-8') as file:
        reader = csv.DictReader(file, delimiter=';')
        for row in reader:
            try:
                locale = row['locale']
                source = row['source']
                target = row['target']
                translation_id = find_translation_id(translations, locale, source)
                if translation_id:
                    update_translation(translation_id, target)
                else:
                    add_translation(locale, source, target)
            except KeyError as e:
                logger.error(f"Missing key {e} in CSV row. Skipping this row.")
            except Exception as e:
                logger.error(f"An error occurred: {e}")

# Example usage
csv_file_path = 'test.csv'
add_or_update_translations_from_csv(csv_file_path)

Basically is loads the csv file which is set up as

locale;source;target
de-de;Customer;DSB
de-de;Organization;Schule

Looks case sensitively for the source in the whole translations then adds the target as translation for the defined locale

It’s hacky, but it works

Have fun!

2 Likes

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.