Skip to content

Commit c186f2b

Browse files
mtopo27priscilawebdev
authored andcommitted
chore(preprod): add minify localized string instruction (EME-506) (#102457)
add modal to include instructions for minifying strings <img width="828" height="787" alt="image" src="https://github.com/user-attachments/assets/bf60c826-02a0-40b9-84c2-bc0950ccc28b" /> ### Legal Boilerplate Look, I get it. The entity doing business as "Sentry" was incorporated in the State of Delaware in 2015 as Functional Software, Inc. and is gonna need some rights from me in order to utilize my contributions in this here PR. So here's the deal: I retain all rights, title and interest in and to my contributions, and by keeping this boilerplate intact I confirm that Sentry can use, modify, copy, and redistribute my contributions, under Sentry's choice of terms.
1 parent e7c47e7 commit c186f2b

File tree

2 files changed

+146
-0
lines changed

2 files changed

+146
-0
lines changed

static/app/views/preprod/buildDetails/main/insights/appSizeInsightsSidebarRow.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {t, tn} from 'sentry/locale';
1414
import {formatBytesBase10} from 'sentry/utils/bytes/formatBytesBase10';
1515
import {formatPercentage} from 'sentry/utils/number/formatPercentage';
1616
import {openAlternativeIconsInsightModal} from 'sentry/views/preprod/buildDetails/main/insights/alternativeIconsInsightInfoModal';
17+
import {openMinifyLocalizedStringsModal} from 'sentry/views/preprod/buildDetails/main/insights/minifyLocalizedStringsModal';
1718
import {openOptimizeImagesModal} from 'sentry/views/preprod/buildDetails/main/insights/optimizeImagesModal';
1819
import type {
1920
FileSavingsResultGroup,
@@ -39,6 +40,7 @@ export function formatUpside(percentage: number): string {
3940
const INSIGHTS_WITH_MORE_INFO_MODAL = [
4041
'image_optimization',
4142
'alternate_icons_optimization',
43+
'localized_strings_minify',
4244
];
4345

4446
const DEFAULT_ITEMS_PER_PAGE = 20;
@@ -71,6 +73,8 @@ export function AppSizeInsightsSidebarRow({
7173
openAlternativeIconsInsightModal();
7274
} else if (insight.key === 'image_optimization') {
7375
openOptimizeImagesModal(platform);
76+
} else if (insight.key === 'localized_strings_minify') {
77+
openMinifyLocalizedStringsModal();
7478
}
7579
};
7680

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
import {openInsightInfoModal} from 'sentry/actionCreators/modal';
2+
import {CodeBlock} from 'sentry/components/core/code';
3+
import {Flex} from 'sentry/components/core/layout';
4+
import {Text} from 'sentry/components/core/text';
5+
import {Heading} from 'sentry/components/core/text/heading';
6+
import {t, tct} from 'sentry/locale';
7+
import {
8+
CodeBlockWrapper,
9+
InlineCode,
10+
} from 'sentry/views/preprod/buildDetails/main/insights/insightInfoModal';
11+
12+
const COMMENT_EXAMPLE = `/* Title for the expired code alert. */
13+
"code_expired" = "Code Expired";`;
14+
15+
const STRIP_STRINGS_SCRIPT = `#!/usr/bin/env python3
16+
import json
17+
import os
18+
import subprocess
19+
20+
21+
def minify(file_path: str) -> None:
22+
subprocess.run(["plutil", "-convert", "json", file_path], check=True)
23+
24+
with open(file_path, "r", encoding="utf-8") as source:
25+
data = json.load(source)
26+
27+
with open(file_path, "w", encoding="utf-8") as target:
28+
for key, value in data.items():
29+
target.write(f'"{key}" = "{value}";\\n')
30+
31+
32+
for root, _, files in os.walk(os.environ["BUILT_PRODUCTS_DIR"], followlinks=True):
33+
for filename in files:
34+
if filename.endswith(".strings"):
35+
path = os.path.join(root, filename)
36+
print(f"Minifying {path}")
37+
minify(path)`;
38+
39+
function getMinifyLocalizedStringsContent() {
40+
return (
41+
<Flex direction="column" gap="2xl">
42+
<Text>
43+
{t(
44+
'Xcode localized string bundles often ship with translator comments, whitespace, and legacy encodings that the runtime never reads. Trimming that excess reduces download size without touching what users see.'
45+
)}
46+
</Text>
47+
48+
<Flex direction="column" gap="xl">
49+
<Flex direction="column" gap="md">
50+
<Heading as="h3" size="md">
51+
{t('Option 1: Keep the format lean')}
52+
</Heading>
53+
<ul>
54+
<li>
55+
<Text>
56+
{tct(
57+
'Encode localized strings as plain text ([example]), not binary plists. Set [setting] ([key]) to [value] in Xcode.',
58+
{
59+
example: <InlineCode>"key" = "value";</InlineCode>,
60+
setting: <InlineCode>Strings File Output Encoding</InlineCode>,
61+
key: <InlineCode>STRINGS_FILE_OUTPUT_ENCODING</InlineCode>,
62+
value: <InlineCode>UTF-8</InlineCode>,
63+
}
64+
)}
65+
</Text>
66+
</li>
67+
</ul>
68+
</Flex>
69+
70+
<Flex direction="column" gap="md">
71+
<Heading as="h3" size="md">
72+
{t('Option 2: Strip comments automatically')}
73+
</Heading>
74+
<Text>
75+
{t(
76+
'String files can have comments that ship with the bundle. They help during translation but take space in production. A typical comment may look like:'
77+
)}
78+
</Text>
79+
<CodeBlockWrapper>
80+
<CodeBlock language="text" filename="Localizable.strings">
81+
{COMMENT_EXAMPLE}
82+
</CodeBlock>
83+
</CodeBlockWrapper>
84+
<Text>
85+
{t(
86+
'You can automatically strip comments by adding a Run Script build phase that converts each `.strings` file to JSON, rewrites it without comments, and leaves a compact UTF-8 file behind:'
87+
)}
88+
</Text>
89+
<ol>
90+
<li>
91+
<Text>
92+
{tct(
93+
'In Xcode, open [menu] and add a new Run Script phase after the localized resources step.',
94+
{
95+
menu: (
96+
<InlineCode>Build Phases → + → New Run Script Phase</InlineCode>
97+
),
98+
}
99+
)}
100+
</Text>
101+
</li>
102+
<li>
103+
<Text>
104+
{tct(
105+
'Point the shell to your Python 3 binary (for Homebrew on Apple Silicon: [binary]).',
106+
{binary: <InlineCode>/opt/homebrew/bin/python3</InlineCode>}
107+
)}
108+
</Text>
109+
</li>
110+
<li>
111+
<Text>
112+
{t('Paste the script below and commit your annotated originals.')}
113+
</Text>
114+
</li>
115+
</ol>
116+
<Text>
117+
{t(
118+
'The script converts each `.strings` file to JSON, rewrites it without comments, and leaves a compact UTF-8 file behind.'
119+
)}
120+
</Text>
121+
<CodeBlockWrapper>
122+
<CodeBlock language="python" filename="minify_strings.py">
123+
{STRIP_STRINGS_SCRIPT}
124+
</CodeBlock>
125+
</CodeBlockWrapper>
126+
<Text>
127+
{t(
128+
'This script strips comments and blank lines after the files are generated, so keep the original annotated copies under version control for translators.'
129+
)}
130+
</Text>
131+
</Flex>
132+
</Flex>
133+
</Flex>
134+
);
135+
}
136+
137+
export function openMinifyLocalizedStringsModal() {
138+
openInsightInfoModal({
139+
title: t('Minify localized strings'),
140+
children: getMinifyLocalizedStringsContent(),
141+
});
142+
}

0 commit comments

Comments
 (0)