NSLocalizedString shows raw key instead of loading a string from another language - ios

I'm having trouble using NSLocalizedString(key, comment: "") to load strings from Localizable.strings when the key is missing for the current language. NSLocalizedString returns a raw key
For instance, when string is present for English localization, but is missing for Russian:
"config.updating" = "Update in progress...";
Calling NSLocalizedString when iOS language set to Russian returns "config.updating"
NSLocalizedString("config.updating", comment: "") // "config.updating"
Shouldn't NSLocalizedString access the "AppleLanguages" key in NSUserDefaults to determine what the user's settings are and pick some other string?

No, the documentation for NSLocalizedString(key,comment) is pretty clear -
The initial value for key in the strings file will be key. Use the
NSLocalizedStringWithDefaultValue macro to specify another value for
key.
What else would you expect it to return? The code simply looks up the key in a dictionary. It has no idea what message is associated with the key, let alone how to translate that message into Russian.

You can probably create a Build Phase run script where you compare the keys of your translation between your base (say its English) with Russian and then if there is any difference you can either stop the build (exit 1 after echo "error:...") and show a build error with the missing keys as output or you can just show them as error and not stop the build.
1) In your Build Phase Run Script:
MISSING_KEYS_TRANSLATIONS=$(diff <($SRCROOT/tools/localization/check_missing_keys_in_translations.sh en) <($SRCROOT/tools/localization/check_missing_keys_in_translations.sh ru))
if [ "$MISSING_KEYS_TRANSLATIONS" ]; then
echo "error: $MISSING_KEYS_TRANSLATIONS"
fi
2) I have created in my project root folder a folder path like this tools/localization/ where I have put a bash script check_missing_keys_in_translations.sh:
#!/bin/sh
plutil -convert json 'ProjectRootFolder/Resources/Localization/'"$1"'.lproj/Localizable.strings' -o - | ruby -r json -e 'puts JSON.parse(STDIN.read).keys.sort'
3) Don't forget to make your script executable:
chmod a+x check_missing_keys_in_translations.sh

Related

How to fix internal link issues when publishing a Docusaurus site on GitLab pages

In my Docusaurus project my internal links work on my local environment, but when I push to GitLab they no longer work. Instead of replacing the original doc title with the new one it adds it to the url at the end ('https://username.io/test-site/docs/overview/add-a-category.html'). I looked over my config file, but I do not understand why this is happening.
I tried updating the id in the front matter for the page, and making sure it matches the id in the sidebars.json file. I have also added customDocsPath and set it to 'docs/' in the config file, though that is supposed to be the default.
---
id: "process-designer-overview"
title: "Process Designer Overview"
sidebar_label: "Overview"
---
# Process Designer
The Process Designer is a collaborative business process modeling and
design workspace for the business processes, scenarios, roles and tasks
that make up governed data processes.
Use the Process Designer to:
- [Add a Category](add-a-category.html)
- [Add a Process or Scenario](Add%20a%20Process%20or%20Scenario.html)
- [Edit a Process or Scenario](Edit%20a%20Process%20or%20Scenario.html)
I updated the add a category link in parenthesis to an md extension, but that broke the link on my local and it still didn't work on GitLab. I would expect that when a user clicks on the link it would replace the doc title in the url with the new doc title ('https://username.gitlab.io/docs/add-a-category.html') but instead it just tacks it on to the end ('https://username.gitlab.io/docs/process-designer-overview/add-a-category.html') and so the link is broken as that is not where the doc is located.
There were several issues with my links. First, I converted these files from html to markdown using Pandoc and did not add front matter - relying instead on the file name to connect my files to the sidebars. This was fine, except almost all of the file names had spaces in them, which you can see in my code example above. This was causing real issues, so I found a Bash script to replace all of the spaces in my file names with underscores, but now all of my links were broken. I updated all of the links in my files with a search and replace in my code editor, replacing "%20" with "_". I also needed to replace the ".html" extension with ".md" or my project would no longer work locally. Again, I did this with a search and replace in my code editor.
Finally, I ended up adding the front matter because otherwise my sidebar titles were all covered in underscores. Since I was working with 90 files, I didn't want to do this manually. I looked for a while and found a great gist by thebearJew and adjusted it so that it would take the file name and add it as the id, and the first heading and add it as the title and sidebar_label, since as it happens that works for our project. Here is the Bash script I found online to convert the spaces in my file names to underscores if interested:
find $1 -name "* *.md" -type f -print0 | \
while read -d $'\0' f; do mv -v "$f" "${f// /_}"; done
Here is the script I ended up with if anyone else has a similar setup and doesn't want to update a huge amount of files with front matter:
# Given a file path as an argument
# 1. get the file name
# 2. prepend template string to the top of the source file
# 3. resave original source file
# command: find . -name "*.md" -print0 | xargs -0 -I file ./prepend.sh file
filepath="$1"
file_name=$("basename" -a "$filepath")
# Getting the file name (title)
md='.md'
title=${file_name%$md}
heading=$(grep -r "^# \b" ~/Documents/docs/$title.md)
heading1=${heading#*\#}
# Prepend front-matter to files
TEMPLATE="---
id: $title
title: $heading1
sidebar_label: $heading1
---
"
echo "$TEMPLATE" | cat - "$filepath" > temp && mv temp "$filepath"

In Xcode run-script how can I pring the real value from plist edited by xcconfig

I have my normal project and the default plist file, and I also created a xcconfig file.
First I added one key-value in my plist whose key is called custom_mode and value is connected to the value in xcconfig file like this:
//In .plist file
<dict>
<key>custom_mode</key>
<string>$(xcconfig_mode)</string>
</dict>
Second, in my xcconfig file it is set like this:
//In .xcconfig file
xconfig_mode = debugMode
Last I created one script trying to fetch and print the value like this:
//In .script file
script_mode=$(/usr/libexec/PlistBuddy -c 'Print custom_mode' "${INFOPLIST_FILE}")
echo "plist value for custom_mode: ${custom_mode}"
When I finished the above steps and run the app, the script is printing but only it is like
"plist value for custom_mode: $(xcconfig_mode)"
It didn't print the real value set by xcconfig file but the variable name. So how can I be able to get the real value set by xcconfig?
Assuming you are running this script in a build phase script here the build settings are available as environment variables when you can use this:
script_mode_var=$(/usr/libexec/PlistBuddy -c 'Print custom_mode' "${INFOPLIST_FILE}")
script_mode=${!script_mode_var}
From man bash:
If the first character of parameter is an exclamation point (!), it
introduces a level of variable indirection. Bash uses the value of the
variable formed from the rest of parameter as the name of the
variable; this variable is then expanded and that value is used in the
rest of the substitution, rather than the value of parameter itself.
An alternative way is to take the value from the info.plist that Xcode has already processed(and replaced the variables with their value). This can be found in the path plist="$TARGET_BUILD_DIR/$INFOPLIST_PATH". So you can modify you script as such:
plist="$TARGET_BUILD_DIR/$INFOPLIST_PATH"
script_mode=$(/usr/libexec/PlistBuddy -c 'Print custom_mode' "${plist}")

How bobril translation import/export works in bobril-build?

How bb translation works together?
When I used bb b -l 1 worked fine but there is still needed to rewrite all strings for other languages.
bb t -a adds new language, e.g. "cs-CZ" and creates json file with language code.
The question is how can I export/import all strings into json file to translation?
bb t -e - fileName is json or js in dist? Export doesn't work in my case no strings are exported.
bb t -e filename.txt -l cs-CZ is correct way to export untranslated strings to text file with very simple structure. After it will get back from translation agency you can just import it by bb t -i filename.txt -l cs-CS.
Before exporting always update translation files by bb b -l 1 -u 1 as you already find out. Actual JSON files in translations directory contains array of arrays of 3 or 4 items [original, hint, 0/1 - with/out parameters, translation]. So you can directly translate them if you will create some editor for these...
Also please update bobril-build to 0.56.1, I just fixed wrong error message in export even-though everything was ok. Maybe that confuse you so you have to ask, sorry for that.

Weird hidden characters in exported XLIFF file

Whenever I try to 'Export For Internationalization', the exported file contains a weird hidden character, making it unparsable for XLIFF editors. The problem seemed to be in the original .string files, somehow the weird character was inserted in those files. I have since deleted the weird character but whenever I export it still sneaks into the xliff file. I tried cleaning and rebuilding the project, restarting Xcode... none of that seems to work.
Is Xcode somehow using a cached version of the 'bad' .strings file containing the bad character?
Using Xcode
If I try Editor > Export For Localization
I get:
/usr/bin/xmllint exited with status 1
Using Terminal
When I run it from Terminal like so:
xcodebuild -exportLocalizations -localizationPath
/Users/Kymer/Downloads/Wolf -project Wolf.xcodeproj -exportLanguage fr
I get the following errors:
parser error : attributes construct error
parser error : Couldn't find end of Start Tag trans-unit
parser error : PCDATA invalid Char value 19
parser error : PCDATA invalid Char value 19
parser error : Opening and ending tag mismatch
parser error : invalid character in attribute value
parser error : attributes construct error
parser error : Couldn't find end of Start Tag
parser error : PCDATA invalid Char value
/Uxcodebuild: error: /usr/bin/xmllint exited with status 1
In both cases the exported xliff file contains the weird hidden character upon inspection with Sublime Text:
If I manually remove the bad characters the file is perfectly readable by xliff-editors but that's not a good long-term solution of course.
I found the problem: when exporting to an XLIFF file Xcode doesn't look at your .string files, it is all generated from the project itself (i.e. it looks at all NSLocalizedString calls and your storyboards). Which makes sense. I found the weird hidden character in one of my code files. Removing it from the source file fixed the export issue.
Easiest XLIFF workflow
I'll also mention this for future reference: the easiest way to add a new language to your project is to first use the command line:
cd to the your project and run:
xcodebuild -exportLocalizations -localizationPath <path> -project <projectname>.xcodeproj -exportLanguage <language code>
That creates a new XLIFF file and will correctly set the target language in the file (source language will be your base language). A translator can now easily add all necessary translations. Afterwards you can import the translated XLIFF file back into Xcode (select target and Editor > Import localizations). Xcode will then generate all necessary .string files.
Updating existing language: If you add new UI elements and want to update an existing localization language, you can simply export an existing localization (select target and Editor > Export for localization). That XLIFF file will contain all previous translations together with the new strings. A translator simply has to fill in the 'blank' lines. There's no need to touch the .string files yourself, because managing that manually is a pain (especially with the crazy Storyboard ID's).

How can I automatically check for missing localizations in Xcode?

SourceFile.m
NSLocalizedString(#"Word 1", #"");
NSLocalizedString(#"Word 2", #"");
de.lproj/Localizable.strings
"Word 1" = "Wort 1";
"Word 2" = "Wort 2";
fr.lproj/Localizable.strings
/* Missing Word 1 */
"Word 2" = "Mot 2";
Is there a script or a compiler setting that will check that all localised strings are translated in all supported locales?
You can use diff on the list of keys to see what's missing
Here's a shell script (let's call it keys.sh) to print out the keys of a given .strings file, sorted to stdout:
#!/bin/sh
plutil -convert json "$1".lproj/Localizable.strings -o - | ruby -r json -e 'puts JSON.parse(STDIN.read).keys.sort'
You can then use it combined with the <(cmd) shell syntax to compare keys between two localisations; for example to compare your Base.lproj and fr.lproj:
diff <(keys.sh Base) <(keys.sh fr)
Go under "Edit Scheme > Options" and check the "Show non-localized strings" box.
When you Build and Run you'll able to see warnings on Xcode command screen.
if you localized string like below:
lblTitle.text = NSLocalizedString("Lorem Ipsum", "")
then Xcode should throw an error message on terminal like below:
ERROR Lorem Ipsum not found in table Localizable of bundle CFBundle ...
For storyboards, Xcode will throw a similar error.
Not the perfect solution for your problem. But you could uses following plugin to check localization strings while coding.
https://github.com/questbeat/Lin
Also, I use to export localization string table from an Excel file or Google Sheet as a practice. This will make things easier and reduce lot of mistakes.
Check my example on how you can achieve it
To sum up: you can create a Run Script under Build Phase in which you execute a bash script like suggested from #AliSoftware to compare your Localizable.strings and in case some keys are missing from one compared to the other you could either stop the build and output those missing keys as error or you could just output them as error and not let the build continue.

Resources