স্ট্রিং.এক্সএমএলে অন্য স্ট্রিং থেকে এক স্ট্রিংয়ের রেফারেন্স?


230

আমি আমার স্ট্রিং.এক্সএমএল ফাইলে অন্য স্ট্রিং থেকে একটি স্ট্রিং উল্লেখ করতে চাই, নীচের মতো (বিশেষত "ম্যাসেজ_টেক্সট" স্ট্রিং সামগ্রীর শেষটি নোট করুন):

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="button_text">Add item</string>
    <string name="message_text">You don't have any items yet! Add one by pressing the \'@string/button_text\' button.</string>
</resources>

আমি উপরের সিনট্যাক্সটি চেষ্টা করেছি তবে তারপরে পাঠ্যটি "@ স্ট্রিং / বোতাম_পদ্ধতি" স্পষ্ট পাঠ্য হিসাবে প্রিন্ট করে। আমি যা চাই তা নয় আমি বার্তাটির পাঠ্যটি মুদ্রণ করতে চাই "আপনার কাছে এখনও কোনও আইটেম নেই! 'আইটেম যুক্ত করুন' বোতাম টিপে একটি যুক্ত করুন।"

আমি যা চাই তা অর্জনের কোনও জ্ঞাত উপায় আছে কি?

রেশনএল:
আমার অ্যাপ্লিকেশনটিতে আইটেমগুলির একটি তালিকা রয়েছে, তবে সেই তালিকাটি খালি হলে আমি তার পরিবর্তে একটি "@ অ্যান্ড্রয়েড: আইডি / খালি" টেক্সটভিউ দেখি। টেক্সটভিউয়ের পাঠ্যটি হ'ল ব্যবহারকারীকে কীভাবে একটি নতুন আইটেম যুক্ত করতে হয় তা অবহিত করা। আমি আমার লেআউটটিকে পরিবর্তনগুলি বোকা-প্রমাণ হিসাবে তৈরি করতে চাই (হ্যাঁ, আমি প্রশ্নে বোকা :-)


3
অনুরূপ অন্য প্রশ্নের এই উত্তরটি আমার পক্ষে কাজ করেছিল। কোনও জাভা দরকার নেই, তবে এটি কেবল একই সংস্থান ফাইলের মধ্যে কাজ করে works
এমপিকিথ

উত্তর:


253

জাভা কোড: উত্স ব্যবহার না করে এক্সএমএলে প্রায়শই ব্যবহৃত স্ট্রিং (যেমন অ্যাপ্লিকেশন নাম) inোকানোর একটি দুর্দান্ত উপায়

    <?xml version="1.0" encoding="utf-8"?>
    <!DOCTYPE resources [
      <!ENTITY appname "MyAppName">
      <!ENTITY author "MrGreen">
    ]>

<resources>
    <string name="app_name">&appname;</string>
    <string name="description">The &appname; app was created by &author;</string>
</resources>

হালনাগাদ:

এমনকি আপনি আপনার সত্তাকে বিশ্বব্যাপী সংজ্ঞা দিতে পারেন:

মাঝামাঝি / কাঁচা / entities.ent:

<!ENTITY appname "MyAppName">
<!ENTITY author "MrGreen">

মাঝামাঝি / মান / string.xml:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE resources [
    <!ENTITY % ents SYSTEM "./res/raw/entities.ent">
    %ents;   
]>

<resources>
    <string name="app_name">&appname;</string>
    <string name="description">The &appname; app was created by &author;</string>
</resources>

9
এটি ওপি-র সঠিক উত্তর। এই সমাধানের আরও দুর্দান্ত সুবিধাগুলি রয়েছে: (1) আপনি কোনও বাহ্যিক ফাইলে ডিটিডি সংজ্ঞায়িত করতে পারেন এবং আপনার সংস্থার সর্বত্র প্রতিস্থাপন প্রয়োগ করার জন্য এটি কোনও সংস্থান ফাইল থেকে উল্লেখ করতে পারেন। (২) অ্যান্ড্রয়েড স্টুডিও আপনাকে সংজ্ঞায়িত সংস্থাগুলির নাম / রেফারেন্স / রিফ্যাক্টর দেয়। যদিও এটি লেখার সময় স্বতঃসিদ্ধ হয় না। (androidstudio 2.2.2)
মাউরো পাঞ্জেরি

3
@ আরজেফারেস আপনি ২ টি পথে যেতে পারেন: (ক) পুরো সত্তা ফাইল ইজি "সহ": এই উত্তরটি দেখুন । বা (খ) : এখানে প্রদর্শিত হিসাবে বাহ্যিক ডিটিডি সংজ্ঞায়িত প্রতিটি একক সত্তা সহ । মনে রাখবেন যে কোনওটিই নিখুঁত নয় কারণ (ক) আপনি "রিফ্যাক্টরিং" সক্ষমতাগুলি শিথিল করবেন এবং (খ) খুব ভার্চুয়াল
মুরো পাঞ্জেরি

5
আপনি যদি এটিকে অ্যান্ড্রয়েড লাইব্রেরি প্রকল্পে ব্যবহার করেন তবে সাবধানতা অবলম্বন করুন - আপনি এটি আপনার অ্যাপটিতে ওভাররাইট করতে পারবেন না।
zyamys

4
গ্রেড ফাইলের স্বাদগুলি নির্ধারণ করার সময় কি সত্তার মান পরিবর্তন করা সম্ভব?
মায়োচ

7
: বহিরাগত সত্ত্বা আর অ্যান্ড্রয়েড স্টুডিও দ্বারা সমর্থিত না, যেহেতু একটি বাগ এখানে আলোচনা stackoverflow.com/a/51330953/8154765
Davide Cannizzo

181

যতক্ষণ না আপনার পুরো স্ট্রিংয়ে রেফারেন্সের নামটি অন্তর্ভুক্ত থাকে ততক্ষণ একজনের মধ্যে অন্যের মধ্যে রেফারেন্স দেওয়া সম্ভব। উদাহরণস্বরূপ এটি কাজ করবে:

<string name="app_name">My App</string>
<string name="activity_title">@string/app_name</string>
<string name="message_title">@string/app_name</string>

এটি ডিফল্ট মান নির্ধারণের জন্য আরও বেশি কার্যকর:

<string name="string1">String 1</string>
<string name="string2">String 2</string>
<string name="string3">String 3</string>
<string name="string_default">@string/string1</string>

এখন আপনি string_defaultআপনার কোডের যে কোনও জায়গায় ব্যবহার করতে পারবেন এবং যে কোনও সময় আপনি সহজেই ডিফল্ট পরিবর্তন করতে পারেন।


যা এই প্রশ্নেরও উত্তর দেয়: আমি কীভাবে কোনও ক্রিয়াকলাপের শিরোনামে অ্যাপ_নাম স্ট্রিংটি উল্লেখ করব। :)
স্টিফেন হোসিং

53
এটি "যতক্ষণ আপনি পুরো স্ট্রিংটি রেফারেন্স করেন না" (যা আপনি সর্বদা সংজ্ঞা অনুসারে করতে চান) পড়তে হবে না তবে "যতক্ষণ রেফারিং স্ট্রিং রিসোর্স কেবলমাত্র রেফারেন্সের নাম নিয়ে গঠিত"।
sschuberth

54
এটি প্রকৃতপক্ষে কোনও রেফারেন্স নয়, এটি কেবল একটি উপনাম, যা রচনাগুলির স্ট্রিংয়ের সমস্যাটি সমাধান করে না।
এরিক উডরুফ

2
এটি প্রশ্নের উত্তর দেয় না, তারা একটি স্ট্রিং অন্যটিতে এম্বেড করতে চেয়েছিল।
ইন্ট্রিপিডিস

1
এফডাব্লুআইডাব্লু, এটি আমার পক্ষে অত্যন্ত কার্যকর ছিল। ধন্যবাদ.
এলেন স্পারটাস

95

আমার মনে হয় আপনি পারবেন না। তবে আপনি নিজের পছন্দ মতো স্ট্রিংকে "ফর্ম্যাট" করতে পারেন:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="button_text">Add item</string>
    <string name="message_text">You don't have any items yet! Add one by pressing the %1$s button.</string>
</resources>

কোডে:

Resources res = getResources();
String text = String.format(res.getString(R.string.message_text),
                            res.getString(R.string.button_text));

5
আমি আসলে একটি "অ-যুক্তিযুক্ত" সমাধানের জন্য আশা করছিলাম। তবুও একটি উপযুক্ত উত্তর (এবং এর নিখুঁত গতি আপনাকে সবুজ চেক চিহ্ন দেয় :-)
dbm

34
String text = res.getString(R.string.message_text, res.getString(R.string.button_text));একটু ক্লিনার।
আন্দ্রে নভিকভ

34

অ্যান্ড্রয়েডে আপনি এক্সএমএলের অভ্যন্তরে স্ট্রিংগুলিকে সংযুক্ত করতে পারবেন না

নিম্নলিখিত সমর্থিত নয়

<string name="string_default">@string/string1 TEST</string>

এটি কীভাবে অর্জন করা যায় তা জানতে নীচের লিঙ্কটি দেখুন

অ্যান্ড্রয়েড এক্সএমএলে একাধিক স্ট্রিং সংযুক্ত করতে কীভাবে?


16
ওয়েল, মজার গল্প: আপনি উল্লেখ করছেন একই একই প্রশ্নের আমার উত্তর :-)
ডিবিএম

এই অর্জন করার জন্য একটি উপায় আছে কি?

এটি কীভাবে প্রোগ্রামিকভাবে কোনও স্ট্রিং প্রতিস্থাপন করতে পারে তা @ ফ্রেঞ্চসো লরিটা উত্তরের একটি সদৃশ।
কুলমাইন্ড

14

আমি সহজ গ্রেড প্লাগইন তৈরি করেছি যা আপনাকে অন্যের থেকে একটি স্ট্রিং উল্লেখ করতে দেয়। আপনি অন্য ফাইলগুলিতে সংজ্ঞায়িত স্ট্রিংগুলি উল্লেখ করতে পারেন, উদাহরণস্বরূপ বিভিন্ন বিল্ড বৈকল্পিক বা লাইব্রেরিতে। এই পদ্ধতির ধারণা - আইডিই রিফ্যাক্টর এরকম উল্লেখগুলি খুঁজে পাবে না।

{{string_name}}একটি স্ট্রিং উল্লেখ করতে সিনট্যাক্স ব্যবহার করুন :

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="super">Super</string>
    <string name="app_name">My {{super}} App</string>
    <string name="app_description">Name of my application is: {{app_name}}</string>
</resources>

প্লাগইন একীভূত করতে কেবল আপনার অ্যাপ বা লাইব্রেরি মডিউল স্তরের build.gradleফাইলের মধ্যে পরবর্তী কোড যুক্ত করুন

buildscript {
  repositories {
    maven {
      url "https://plugins.gradle.org/m2/"
    }
  }
  dependencies {
    classpath "gradle.plugin.android-text-resolver:buildSrc:1.2.0"
  }
}

apply plugin: "com.icesmith.androidtextresolver"

আপডেট: লাইব্রেরি অ্যান্ড্রয়েড গ্রেড প্লাগইন সংস্করণ 3.0 এবং এর সাথে কাজ করে না কারণ প্লাগইনের নতুন সংস্করণ aapt2 ব্যবহার করে যা রিসোর্সকে .ফ্লাট বাইনারি ফর্ম্যাটে প্যাক করে, তাই প্যাক করা সংস্থানগুলি লাইব্রেরির জন্য অনুপলব্ধ। একটি অস্থায়ী সমাধান হিসাবে আপনি আপনার গ্রেড.প্রপ্রেটিস ফাইলে android.enableAapt2 = মিথ্যা সেট করে aapt2 অক্ষম করতে পারেন।


আমি এই ধারণাটি পছন্দ করি .. তবে এটি আমার জন্য এই ত্রুটিটির সাথে ব্যর্থ:> Could not get unknown property 'referencedString'
jpage4500

এটি aapt2 এর সাথে বিরতি দেয়
স্নিকোলাস

2
আমি এমন একটি প্লাগইন তৈরি করেছি যা বেশ কিছুটা একই কাজ করে এবং এ্যাপ্ট 2: গিথুব. com/ লাইক দ্য স্যালাড / অ্যান্ড্রয়েড- স্ট্রিং- রেফারেন্স :) এর সাথে কাজ করে :)
সিজার

7

আপনি নিজের যুক্তিটি ব্যবহার করতে পারেন যা নীড়যুক্ত স্ট্রিংগুলিকে পুনরাবৃত্তি করে সমাধান করে।

/**
 * Regex that matches a resource string such as <code>@string/a-b_c1</code>.
 */
private static final String REGEX_RESOURCE_STRING = "@string/([A-Za-z0-9-_]*)";

/** Name of the resource type "string" as in <code>@string/...</code> */
private static final String DEF_TYPE_STRING = "string";

/**
 * Recursively replaces resources such as <code>@string/abc</code> with
 * their localized values from the app's resource strings (e.g.
 * <code>strings.xml</code>) within a <code>source</code> string.
 * 
 * Also works recursively, that is, when a resource contains another
 * resource that contains another resource, etc.
 * 
 * @param source
 * @return <code>source</code> with replaced resources (if they exist)
 */
public static String replaceResourceStrings(Context context, String source) {
    // Recursively resolve strings
    Pattern p = Pattern.compile(REGEX_RESOURCE_STRING);
    Matcher m = p.matcher(source);
    StringBuffer sb = new StringBuffer();
    while (m.find()) {
        String stringFromResources = getStringByName(context, m.group(1));
        if (stringFromResources == null) {
            Log.w(Constants.LOG,
                    "No String resource found for ID \"" + m.group(1)
                            + "\" while inserting resources");
            /*
             * No need to try to load from defaults, android is trying that
             * for us. If we're here, the resource does not exist. Just
             * return its ID.
             */
            stringFromResources = m.group(1);
        }
        m.appendReplacement(sb, // Recurse
                replaceResourceStrings(context, stringFromResources));
    }
    m.appendTail(sb);
    return sb.toString();
}

/**
 * Returns the string value of a string resource (e.g. defined in
 * <code>values.xml</code>).
 * 
 * @param name
 * @return the value of the string resource or <code>null</code> if no
 *         resource found for id
 */
public static String getStringByName(Context context, String name) {
    int resourceId = getResourceId(context, DEF_TYPE_STRING, name);
    if (resourceId != 0) {
        return context.getString(resourceId);
    } else {
        return null;
    }
}

/**
 * Finds the numeric id of a string resource (e.g. defined in
 * <code>values.xml</code>).
 * 
 * @param defType
 *            Optional default resource type to find, if "type/" is not
 *            included in the name. Can be null to require an explicit type.
 * 
 * @param name
 *            the name of the desired resource
 * @return the associated resource identifier. Returns 0 if no such resource
 *         was found. (0 is not a valid resource ID.)
 */
private static int getResourceId(Context context, String defType,
        String name) {
    return context.getResources().getIdentifier(name, defType,
            context.getPackageName());
}

Activityউদাহরণস্বরূপ, একটি থেকে এটি কল করুন

replaceResourceStrings(this, getString(R.string.message_text));

2

আমি সচেতন যে এটি একটি পুরানো পোস্ট, তবে আমি আমার একটি প্রকল্পের জন্য যে দ্রুত 'নোংরা সমাধান' নিয়ে এসেছি তা ভাগ করে নিতে চাই। এটি কেবল টেক্সটভিউয়ের জন্যই কাজ করে তবে অন্যান্য উইজেটগুলিতেও এটি খাপ খাইয়ে নিতে পারে। নোট করুন যে এর জন্য লিঙ্কটি বর্গাকার বন্ধনীতে আবদ্ধ হওয়া প্রয়োজন (উদাঃ [@string/foo])।

public class RefResolvingTextView extends TextView
{
    // ...

    @Override
    public void setText(CharSequence text, BufferType type)
    {
        final StringBuilder sb = new StringBuilder(text);
        final String defPackage = getContext().getApplicationContext().
                getPackageName();

        int beg;

        while((beg = sb.indexOf("[@string/")) != -1)
        {
            int end = sb.indexOf("]", beg);
            String name = sb.substring(beg + 2, end);
            int resId = getResources().getIdentifier(name, null, defPackage);
            if(resId == 0)
            {
                throw new IllegalArgumentException(
                        "Failed to resolve link to @" + name);
            }

            sb.replace(beg, end + 1, getContext().getString(resId));
        }

        super.setText(sb, type);
    }
}

এই পদ্ধতির downside হয় যে setText()ধর্মান্তরিত CharSequenceএকটি থেকে String, যা একটি বিষয় আপনি একটি ভালো জিনিস পাস SpannableString; আমার প্রকল্পের জন্য এটি কোনও সমস্যা ছিল না যেহেতু আমি কেবল এটির জন্য ব্যবহার করেছি TextViewsআমার নিজের থেকে অ্যাক্সেস করার প্রয়োজন ছিল না Activity


এটি এই প্রশ্নের উত্তরের নিকটতম বিষয়। আমি মনে করি আমাদের xML পার্সিং লেআউটটিতে নজর দেওয়া দরকার।
এরিক উডরুফ

2

নতুন ডেটা বাইন্ডিংয়ের সাহায্যে আপনি আপনার এক্সএমএলকে একত্রিত করতে এবং আরও অনেক কিছু করতে পারেন।

উদাহরণস্বরূপ যদি আপনি মেসেজ 1 এবং ম্যাসেজ 2 পেয়ে থাকেন তবে আপনি:

android:text="@{@string/message1 + ': ' + @string/message2}"

এমনকি আপনি কিছু পাঠ্য ব্যবহার আমদানি করতে পারেন এবং স্ট্রিং.ফর্ম্যাট এবং বন্ধুদের কল করতে পারেন।

দুর্ভাগ্যক্রমে আপনি যদি এটি বেশ কয়েকটি জায়গায় পুনরায় ব্যবহার করতে চান তবে এটি অগোছালো হয়ে যেতে পারে, আপনি কোথাও এই কোড টুকরা চান না। এবং আপনি তাদের এক জায়গায় xML এ সংজ্ঞায়িত করতে পারবেন না (এটি আমার জানা নয়) যাতে আপনি এমন একটি শ্রেণি তৈরি করতে পারেন যা এই রচনাগুলি আবদ্ধ করে তুলবে:

public final class StringCompositions {
    public static final String completeMessage = getString(R.string.message1) + ": " + getString(R.string.message2);
}

তারপরে আপনি এটি পরিবর্তে ব্যবহার করতে পারেন (আপনাকে ডেটা বাইন্ডিং সহ ক্লাসটি আমদানি করতে হবে)

android:text="@{StringCompositions.completeMessage}"

2

ফ্রান্সেসকো লরিটা উপরের উত্তর ছাড়াও https://stackoverflow.com/a/39870268/9400836

মনে হচ্ছে এখানে একটি সংকলন ত্রুটি আছে "& সত্তা; রেফারেন্স করা হয়েছিল, তবে ঘোষিত হয়নি" যা এই জাতীয় বাহ্যিক ঘোষণাকে উল্লেখ করে সমাধান করা যেতে পারে

মাঝামাঝি / কাঁচা / entities.ent

<!ENTITY appname "My App Name">

মাঝামাঝি / মান / strings.xml

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE resources [
    <!ENTITY appname SYSTEM "/raw/entities.ent">
]>
<resources>
    <string name="app_name">&appname;</string>
</resources

যদিও এটি সংকলন করে চালায় এটির একটি খালি মূল্য রয়েছে। সম্ভবত কেউ জানেন যে এটি কীভাবে সমাধান করা যায়। আমি একটি মন্তব্য পোস্ট করতে হবে তবে সর্বনিম্ন খ্যাতি 50।


1
এখন আপনার 53.
কুলমাইন্ড

1

আপনি স্ট্রিং প্লেসোল্ডার (% s) ব্যবহার করতে পারেন এবং রান-টাইমে জাভা ব্যবহার করে তাদের প্রতিস্থাপন করতে পারেন

<resources>
<string name="button_text">Add item</string>
<string name="message_text">Custom text %s </string>
</resources>

এবং জাভা মধ্যে

String final = String.format(getString(R.string.message_text),getString(R.string.button_text));

এবং তারপরে এটি স্ট্রিং ব্যবহার করে এমন স্থানে সেট করুন


আপনি অন্যান্য সমাধান অনুলিপি করুন। বিভিন্ন স্ট্রিং, ব্যবহার রেফারেন্স যখন %1$s, %2$sইত্যাদি পরিবর্তে %s
কুলমাইন্ড

@ কুলমাইন্ড আপনি অনুলিপিটির উল্লেখ উল্লেখ করতে পারেন।
ইসমাইল ইকবাল

1

আমি একটি ছোট লাইব্রেরি তৈরি করেছি যা আপনাকে বিল্ডটাইমের সময় এই স্থানধারকদের সমাধান করার অনুমতি দেয়, তাই আপনি যা চান তা অর্জন করতে আপনাকে কোনও জাভা / কোটলিন কোড যুক্ত করতে হবে না।

আপনার উদাহরণের ভিত্তিতে, আপনাকে আপনার স্ট্রিংগুলি এভাবে সেট আপ করতে হবে:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="button_text">Add item</string>
    <string name="template_message_text">You don't have any items yet! Add one by pressing the ${button_text} button.</string>
</resources>

এবং তারপরে প্লাগইনটি নিম্নলিখিত উত্পন্ন করার যত্ন নেবে:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="message_text">You don't have any items yet! Add one by pressing the Add item button.</string>
</resources>

এটি স্থানীয়করণ এবং স্বাদযুক্ত স্ট্রিংয়ের জন্যও কাজ করে, যখনই আপনি আপনার টেম্পলেট বা এর মানগুলিতে পরিবর্তন করেন তখন উত্পন্ন স্ট্রিংগুলি নিজেকে আপডেট রাখে।

এখানে আরও তথ্য: https://github.com/LikeTheSalad/android-string-references


আমি আপনার লাইব্রেরি চেষ্টা করেছিলাম। আপনার দেওয়া পদক্ষেপগুলি অনুসরণ করার পরে। এটি বিল্ড ত্রুটিগুলি দেয় keeps আপনার গ্রন্থাগারটি মোটেও কাজ করে না
বিকাশকারী

আমি শুনে, শুনে দুঃখিত। আপনি যদি পছন্দ করেন তবে দয়া করে এখানে একটি সমস্যা তৈরি করুন: লগগুলিতে github.com/LikeTheSalad/android-string-references/issues এবং এটির কোনও বৈশিষ্ট্য সমস্যা না হলে বা এটি কোনও কনফিগারেশন সমস্যা থাকলে আমিও সহায়তা করতে পারি তুমি সেখানে 👍
César Muñoz
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.