Skip to content

Commit

Permalink
Merge pull request #26115 from frappe/version-15-hotfix
Browse files Browse the repository at this point in the history
chore: release v15
  • Loading branch information
ankush committed Apr 23, 2024
2 parents f8c02cf + bbe0529 commit 1c930d1
Show file tree
Hide file tree
Showing 105 changed files with 42,665 additions and 763 deletions.
64 changes: 0 additions & 64 deletions .github/helper/documentation.py

This file was deleted.

37 changes: 37 additions & 0 deletions .github/helper/update_pot_file.sh
@@ -0,0 +1,37 @@
#!/bin/bash
set -e
cd ~ || exit

echo "Setting Up Bench..."

pip install frappe-bench
bench -v init frappe-bench --skip-assets --skip-redis-config-generation --python "$(which python)" --frappe-path "${GITHUB_WORKSPACE}"
cd ./frappe-bench || exit

echo "Generating POT file..."
bench generate-pot-file --app frappe

cd ./apps/frappe || exit

echo "Configuring git user..."
git config user.email "developers@erpnext.com"
git config user.name "frappe-pr-bot"

echo "Setting the correct git remote..."
# Here, the git remote is a local file path by default. Let's change it to the upstream repo.
git remote set-url upstream https://github.com/frappe/frappe.git

echo "Creating a new branch..."
isodate=$(date -u +"%Y-%m-%d")
branch_name="pot_${BASE_BRANCH}_${isodate}"
git checkout -b "${branch_name}"

echo "Commiting changes..."
git add .
git commit -m "chore: update POT file"

gh auth setup-git
git push -u upstream "${branch_name}"

echo "Creating a PR..."
gh pr create --fill --base "${BASE_BRANCH}" --head "${branch_name}" -R frappe/frappe
38 changes: 38 additions & 0 deletions .github/workflows/generate-pot-file.yml
@@ -0,0 +1,38 @@
# This workflow is agnostic to branches. Only maintain on develop branch.
# To add/remove branches just modify the matrix.

name: Regenerate POT file (translatable strings)
on:
schedule:
# 9:30 UTC => 3 PM IST Sunday
- cron: "30 9 * * 0"
workflow_dispatch:

jobs:
regeneratee-pot-file:
name: Release
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
branch: ["version-15-hotfix"]
permissions:
contents: write

steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: ${{ matrix.branch }}

- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: Run script to update POT file
run: |
bash ${GITHUB_WORKSPACE}/.github/helper/update_pot_file.sh
env:
GH_TOKEN: ${{ secrets.RELEASE_TOKEN }}
BASE_BRANCH: ${{ matrix.branch }}
19 changes: 0 additions & 19 deletions .github/workflows/linters.yml
Expand Up @@ -31,25 +31,6 @@ jobs:
npm install @commitlint/cli @commitlint/config-conventional
npx commitlint --verbose --from ${{ github.event.pull_request.base.sha }} --to ${{ github.event.pull_request.head.sha }}
docs-required:
name: 'Documentation Required'
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'

steps:
- name: 'Setup Environment'
uses: actions/setup-python@v4
with:
python-version: '3.10'
- uses: actions/checkout@v4

- name: Validate Docs
env:
PR_NUMBER: ${{ github.event.number }}
run: |
pip install requests --quiet
python $GITHUB_WORKSPACE/.github/helper/documentation.py $PR_NUMBER
linter:
name: 'Semgrep Rules'
runs-on: ubuntu-latest
Expand Down
2 changes: 0 additions & 2 deletions .gitignore
Expand Up @@ -2,7 +2,6 @@
*.py~
*.comp.js
*.DS_Store
locale
.wnf-lang-status
*.swp
*.egg-info
Expand Down Expand Up @@ -71,7 +70,6 @@ coverage.xml

# Translations
*.mo
*.pot

# Django stuff:
*.log
Expand Down
9 changes: 9 additions & 0 deletions babel_extractors.csv
@@ -0,0 +1,9 @@
hooks.py,frappe.gettext.extractors.navbar.extract
**/doctype/*/*.json,frappe.gettext.extractors.doctype.extract
**/workspace/*/*.json,frappe.gettext.extractors.workspace.extract
**/onboarding_step/*/*.json,frappe.gettext.extractors.onboarding_step.extract
**/module_onboarding/*/*.json,frappe.gettext.extractors.module_onboarding.extract
**/report/*/*.json,frappe.gettext.extractors.report.extract
**.py,frappe.gettext.extractors.python.extract
**.js,frappe.gettext.extractors.javascript.extract
**.html,frappe.gettext.extractors.html_template.extract
8 changes: 8 additions & 0 deletions crowdin.yml
@@ -0,0 +1,8 @@
files:
- source: /frappe/locale/main.pot
translation: /frappe/locale/%two_letters_code%.po
pull_request_title: "fix: sync translations from crowdin"
pull_request_labels:
- translation
commit_message: "fix: %language% translations"
append_commit_message: false
4 changes: 2 additions & 2 deletions cypress.config.js
Expand Up @@ -11,8 +11,8 @@ module.exports = defineConfig({
viewportHeight: 960,
viewportWidth: 1400,
retries: {
runMode: 2,
openMode: 2,
runMode: 1,
openMode: 1,
},
e2e: {
// We've imported your old cypress plugins here.
Expand Down
2 changes: 1 addition & 1 deletion cypress/integration/workspace_blocks.js
Expand Up @@ -166,7 +166,7 @@ context("Workspace Blocks", () => {

// add number card
cy.fill_field("number_card_name", "Test Number Card", "Link");
cy.get('[data-fieldname="number_card_name"] ul li').contains("Test Number Card").click();
cy.get('[data-fieldname="number_card_name"] ul div').contains("Test Number Card").click();
cy.click_modal_primary_button("Add");
cy.get(".ce-block .number-widget-box").first().as("number_card");
cy.get("@number_card").find(".widget-title").should("contain", "Test Number Card");
Expand Down
91 changes: 76 additions & 15 deletions frappe/__init__.py
Expand Up @@ -90,7 +90,7 @@ def copy(self):


def _(msg: str, lang: str | None = None, context: str | None = None) -> str:
"""Returns translated string in current lang, if exists.
"""Return translated string in current lang, if exists.
Usage:
_('Change')
_('Change', context='Coins')
Expand Down Expand Up @@ -125,8 +125,61 @@ def _(msg: str, lang: str | None = None, context: str | None = None) -> str:
return translated_string or non_translated_string


def as_unicode(text: str, encoding: str = "utf-8") -> str:
"""Convert to unicode if required"""
def _lt(msg: str, lang: str | None = None, context: str | None = None):
"""Lazily translate a string.
This function returns a "lazy string" which when casted to string via some operation applies
translation first before casting.
This is only useful for translating strings in global scope or anything that potentially runs
before `frappe.init()`
Note: Result is not guaranteed to equivalent to pure strings for all operations.
"""
return _LazyTranslate(msg, lang, context)


@functools.total_ordering
class _LazyTranslate:
__slots__ = ("msg", "lang", "context")

def __init__(self, msg: str, lang: str | None = None, context: str | None = None) -> None:
self.msg = msg
self.lang = lang
self.context = context

@property
def value(self) -> str:
return _(str(self.msg), self.lang, self.context)

def __str__(self):
return self.value

def __add__(self, other):
if isinstance(other, str | _LazyTranslate):
return self.value + str(other)
raise NotImplementedError

def __radd__(self, other):
if isinstance(other, str | _LazyTranslate):
return str(other) + self.value
return NotImplementedError

def __repr__(self) -> str:
return f"'{self.value}'"

# NOTE: it's required to override these methods and raise error as default behaviour will
# return `False` in all cases.
def __eq__(self, other):
raise NotImplementedError

def __lt__(self, other):
raise NotImplementedError


def as_unicode(text, encoding: str = "utf-8") -> str:
"""Convert to unicode if required."""
if isinstance(text, str):
return text
elif text is None:
Expand All @@ -137,16 +190,6 @@ def as_unicode(text: str, encoding: str = "utf-8") -> str:
return str(text)


def get_lang_dict(fortype: str, name: str | None = None) -> dict[str, str]:
"""Returns the translated language dict for the given type and name.
:param fortype: must be one of `doctype`, `page`, `report`, `include`, `jsfile`, `boot`
:param name: name of the document for which assets are to be returned."""
from frappe.translate import get_dict

return get_dict(fortype, name)


def set_user_lang(user: str, user_language: str | None = None) -> None:
"""Guess and set user language for the session. `frappe.local.lang`"""
from frappe.translate import get_user_lang
Expand Down Expand Up @@ -2413,9 +2456,22 @@ def safe_encode(param, encoding="utf-8"):
return param


def safe_decode(param, encoding="utf-8"):
def safe_decode(param, encoding="utf-8", fallback_map: dict | None = None):
"""
Method to safely decode data into a string
:param param: The data to be decoded
:param encoding: The encoding to decode into
:param fallback_map: A fallback map to reference in case of a LookupError
:return:
"""
try:
param = param.decode(encoding)
except LookupError:
try:
param = param.decode((fallback_map or {}).get(encoding, "utf-8"))
except Exception:
pass
except Exception:
pass
return param
Expand Down Expand Up @@ -2463,7 +2519,12 @@ def wrapper(*args, **kwargs):


def _register_fault_handler():
faulthandler.register(signal.SIGUSR1)
import io
import sys

# Some libraries monkey patch stderr, we need actual fd
if isinstance(sys.stderr, io.TextIOWrapper):
faulthandler.register(signal.SIGUSR1, file=sys.stderr)


from frappe.utils.error import log_error
Expand Down
2 changes: 2 additions & 0 deletions frappe/boot.py
Expand Up @@ -8,6 +8,7 @@
import frappe.defaults
import frappe.desk.desk_page
from frappe.core.doctype.navbar_settings.navbar_settings import get_app_logo, get_navbar_settings
from frappe.desk.doctype.changelog_feed.changelog_feed import get_changelog_feed_items
from frappe.desk.doctype.form_tour.form_tour import get_onboarding_ui_tours
from frappe.desk.doctype.route_history.route_history import frequently_visited_links
from frappe.desk.form.load import get_meta_bundle
Expand Down Expand Up @@ -107,6 +108,7 @@ def get_bootinfo():
bootinfo.translated_doctypes = get_translated_doctypes()
bootinfo.subscription_conf = add_subscription_conf()
bootinfo.marketplace_apps = get_marketplace_apps()
bootinfo.changelog_feed = get_changelog_feed_items()

return bootinfo

Expand Down
10 changes: 9 additions & 1 deletion frappe/commands/__init__.py
Expand Up @@ -105,14 +105,22 @@ def call_command(cmd, context):

def get_commands():
# prevent circular imports
from .gettext import commands as gettext_commands
from .redis_utils import commands as redis_commands
from .scheduler import commands as scheduler_commands
from .site import commands as site_commands
from .translate import commands as translate_commands
from .utils import commands as utils_commands

clickable_link = "https://frappeframework.com/docs"
all_commands = scheduler_commands + site_commands + translate_commands + utils_commands + redis_commands
all_commands = (
scheduler_commands
+ site_commands
+ translate_commands
+ gettext_commands
+ utils_commands
+ redis_commands
)

for command in all_commands:
if not command.help:
Expand Down

0 comments on commit 1c930d1

Please sign in to comment.