Denna integrationsguide är endast tillgänglig på engelska.
BeMyWords with iOS (.strings)
Integration guide for iOS and macOS apps using Apple's standard Localizable.strings format.
Shape of the integration:
- At build time (or periodically), fetch translations from BeMyWords and convert to
.stringsfiles per language under<Language>.lproj/. - Use
NSLocalizedStringin Swift as normal. - Optionally, push
Base.lproj/Localizable.stringsto BeMyWords as the English master source.
This guide assumes the classic .strings format. If you're on Xcode 15+ with String Catalogs (.xcstrings), the principles are the same but you'd convert to that JSON format on the client side — out of scope here.
Prerequisites
- An Xcode project with at least one
.lprojdirectory (Base or en). - A BeMyWords workspace, project, namespace, and API key.
- Node.js available in your build environment (used for the fetch script — swap for any language you prefer).
1. Environment variables
Typically stored in a build-env file or set in your CI. Locally you can keep them in a gitignored .env at the project root:
BEMYWORDS_BASE_URL=https://www.bemywords.org
BEMYWORDS_PROJECT_ID=<your-project-uuid>
BEMYWORDS_API_TOKEN=<your-api-token>
BEMYWORDS_NAMESPACE=ios
2. Fetch + convert script
scripts/fetch-translations.mjs:
import { writeFileSync, mkdirSync } from "node:fs";
import { join, dirname } from "node:path";
import { fileURLToPath } from "node:url";
const __dirname = dirname(fileURLToPath(import.meta.url));
// Adjust to where your .lproj directories live
const PROJECT_ROOT = join(__dirname, "..", "MyApp");
const BASE_URL = process.env.BEMYWORDS_BASE_URL || "https://www.bemywords.org";
const PROJECT_ID = process.env.BEMYWORDS_PROJECT_ID;
const API_TOKEN = process.env.BEMYWORDS_API_TOKEN;
const NAMESPACE = process.env.BEMYWORDS_NAMESPACE || "ios";
// Map BeMyWords language codes to iOS locale identifiers.
// BeMyWords: en, nb, pt-BR → iOS: en, nb, pt-BR
const LANGUAGES = { en: "en", nb: "nb", "pt-BR": "pt-BR" };
function escapeStringsValue(s) {
return s
.replace(/\\/g, "\\\\")
.replace(/"/g, '\\"')
.replace(/\n/g, "\\n")
.replace(/\r/g, "\\r")
.replace(/\t/g, "\\t");
}
function toStringsFormat(dict) {
const lines = ['/* Generated by fetch-translations.mjs from BeMyWords. Do not edit. */', ''];
for (const [key, value] of Object.entries(dict).sort()) {
lines.push(`"${escapeStringsValue(key)}" = "${escapeStringsValue(value)}";`);
}
return lines.join("\n") + "\n";
}
async function fetchLanguage(bwLang) {
const url = `${BASE_URL}/api/${PROJECT_ID}/latest/${bwLang}/${NAMESPACE}`;
const res = await fetch(url, {
headers: { Authorization: `Token token=${API_TOKEN}` },
});
if (!res.ok) throw new Error(`${bwLang}: HTTP ${res.status}`);
return res.json();
}
async function main() {
if (!PROJECT_ID || !API_TOKEN) {
console.warn("BEMYWORDS_PROJECT_ID or BEMYWORDS_API_TOKEN not set.");
return;
}
for (const [bwLang, iosLocale] of Object.entries(LANGUAGES)) {
const data = await fetchLanguage(bwLang);
const lprojDir = join(PROJECT_ROOT, `${iosLocale}.lproj`);
mkdirSync(lprojDir, { recursive: true });
const stringsPath = join(lprojDir, "Localizable.strings");
writeFileSync(stringsPath, toStringsFormat(data), "utf-8");
console.log(` [${iosLocale}] ${Object.keys(data).length} keys → ${stringsPath}`);
}
}
main().catch((e) => {
console.error(e);
process.exit(1);
});
3. Wire into Xcode build
In Build Phases → New Run Script Phase (place it before "Copy Bundle Resources"):
if [ -f "$SRCROOT/.env" ]; then
set -a; source "$SRCROOT/.env"; set +a
fi
cd "$SRCROOT"
node scripts/fetch-translations.mjs
Uncheck "Based on dependency analysis" so it always runs.
Alternatively, run it manually or via CI before xcodebuild:
node scripts/fetch-translations.mjs
xcodebuild build ...
4. Use in Swift
let title = NSLocalizedString("home.hero.title", value: "Localization for solo devs and small teams", comment: "Home hero title")
let greeting = String(
format: NSLocalizedString("greeting", value: "Hello, %@!", comment: ""),
userName
)
BeMyWords stores iOS format specifiers (%@, %d) verbatim. Use placeholder validation in BeMyWords project settings.
5. (Optional) Push English to BeMyWords
Parse your Base or en Localizable.strings and PUT to BeMyWords:
import { readFileSync } from "node:fs";
const path = join(PROJECT_ROOT, "en.lproj", "Localizable.strings");
const text = readFileSync(path, "utf-8");
// Naive parser — good enough for well-formatted .strings files
const re = /"((?:[^"\\]|\\.)*)"\s*=\s*"((?:[^"\\]|\\.)*)"\s*;/g;
const translations = {};
let match;
while ((match = re.exec(text)) !== null) {
const key = match[1].replace(/\\"/g, '"').replace(/\\\\/g, "\\");
const value = match[2].replace(/\\"/g, '"').replace(/\\\\/g, "\\").replace(/\\n/g, "\n");
translations[key] = value;
}
const url = `${BASE_URL}/api/overwrite/${PROJECT_ID}/latest/en/${NAMESPACE}`;
await fetch(url, {
method: "PUT",
headers: {
Authorization: `Token token=${API_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ translations }),
});
Pluralization
iOS uses .stringsdict files for plurals (XML). That conversion is not covered by this basic script — if you rely heavily on pluralization:
- Store plural variants in BeMyWords as dot-keyed siblings (
apples.one,apples.other). - Write a second generator pass that produces
.stringsdictfrom those keys. - Or switch to String Catalogs (
.xcstrings) which handle plurals natively in JSON.
For small-team apps with few plural strings, it's often simpler to branch in code:
let message = count == 1
? NSLocalizedString("apple.singular", value: "1 apple", comment: "")
: String(format: NSLocalizedString("apple.plural", value: "%d apples", comment: ""), count)
API reference
Troubleshooting
Strings show as keys in the app: Xcode didn't rebuild the .strings files into the bundle. Clean build folder (Shift + Cmd + K) and rebuild.
Quotes / newlines render as literal \" in the UI: the escape function in the script didn't handle the character. Check escapeStringsValue — Apple's .strings format requires \\, \", \n, \r, \t to be backslash-escaped.
Missing translations for a region: BeMyWords uses nb but iOS uses nb, no, or nb-NO depending on language setting. Either add a nb-NO.lproj fallback or rely on iOS's language-tag resolution.
Base vs en.lproj confusion: if you have both Base.lproj/Localizable.strings and en.lproj/Localizable.strings, Xcode may prefer one unpredictably. Pick one as the canonical English location and delete the other; write the fetch script to populate whichever you keep.
Vad kostar BeMyWords?
Gratis att börja: 5 000 ord lagrade, 1 webbplats, inget kort. Betalda nivåer börjar på 199 kr i månaden, eller 1 990 kr för ett år. De räknar orden du lagrar, originalet plus varje översättning av det, och aldrig personer, sidvisningar eller ett tak på hur många språk du kör. Ta med din egen AI-nyckel och det är 199 kr i månaden platt utan ordgräns.
Vilken nivå det är beror på hur många ord din webbplats innehåller. Klistra in din adress så läser vi den och berättar.
Varje nivå, och vad den innehåller Beräkna din webbplats storlekInstallera det på projektet du just läste om.
Den kostnadsfria nivån räcker för att översätta en landningssida och bedöma resultatet själv. Inget kort.
Starta gratis